Protostar net3 write-up
net3
#include "../common/common.c" #define NAME "net3" #define UID 996 #define GID 996 #define PORT 2996 /* * Extract a null terminated string from the buffer */ int get_string(char **result, unsigned char *buffer, u_int16_t len) { unsigned char byte; byte = *buffer; if(byte > len) errx(1, "badly formed packet"); *result = malloc(byte); strcpy(*result, buffer + 1); return byte + 1; } /* * Check to see if we can log into the host */ int login(unsigned char *buffer, u_int16_t len) { char *resource, *username, *password; int deduct; int success; if(len < 3) errx(1, "invalid login packet length"); resource = username = password = NULL; deduct = get_string(&resource, buffer, len); deduct += get_string(&username, buffer+deduct, len-deduct); deduct += get_string(&password, buffer+deduct, len-deduct); success = 0; success |= strcmp(resource, "net3"); success |= strcmp(username, "awesomesauce"); success |= strcmp(password, "password"); free(resource); free(username); free(password); return ! success; } void send_string(int fd, unsigned char byte, char *string) { struct iovec v[3]; u_int16_t len; int expected; len = ntohs(1 + strlen(string)); v[0].iov_base = &len; v[0].iov_len = sizeof(len); v[1].iov_base = &byte; v[1].iov_len = 1; v[2].iov_base = string; v[2].iov_len = strlen(string); expected = sizeof(len) + 1 + strlen(string); if(writev(fd, v, 3) != expected) errx(1, "failed to write correct amount of bytes"); } void run(int fd) { u_int16_t len; unsigned char *buffer; int loggedin; while(1) { nread(fd, &len, sizeof(len)); len = ntohs(len); buffer = malloc(len); if(! buffer) errx(1, "malloc failure for %d bytes", len); nread(fd, buffer, len); switch(buffer[0]) { case 23: loggedin = login(buffer + 1, len - 1); send_string(fd, 33, loggedin ? "successful" : "failed"); break; default: send_string(fd, 58, "what you talkin about willis?"); break; } } } int main(int argc, char **argv, char **envp) { int fd; char *username; /* Run the process as a daemon */ background_process(NAME, UID, GID); /* Wait for socket activity and return */ fd = serve_forever(PORT); /* Set the client socket to STDIN, STDOUT, and STDERR */ set_io(fd); /* Don't do this :> */ srandom(time(NULL)); run(fd); }
对源码进行分析,在run()函数中,首先接收一个len长度,表示接下来的缓冲区buffer大小,然后接收buffer内容,其中要求buffer[0] = 23 = 0x17,然后调用login()函数,根据deduct 表示的长度值来将buffer内容切片,分解为三个字符串
net3 / awesomesauce / password
而deduct值相当于字符串前缀表示的就是该段字符串的长度,后边再加上一个\x00结束符
据此构造处buffer内容为
buf = “\x17” + “\x05net3\x00” + “\x0dawesomesauce\x00” + “\x08password”
根据分析编写python脚本net3.py
from socket import * from struct import * s = socket(AF_INET, SOCK_STREAM) s.connect(("localhost", 2996)) # Send the buf string buf = "\x17" + "\x05net3\x00" + "\x0dawesomesauce\x00" + "\x08password" # Send the buf length as unsigned short (H) and network byte order (!) s.send(pack("!H", len(buf))) s.send(buf) print(s.recv(1024)) s.close()
执行成功
