SPIKEで脆弱性調査の勉強。
とりあえず、脆弱性のあるサーバを探すのもなんなので、適当に作って試します。
実行環境はx86_64のdebian sid。
下が脆弱性のあるエコーサーバ。
while(true)で無限ループしないで一回だけユーザの入力を受け付けてます。
#include <iostream> #include <cstring> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <pthread.h> #include <assert.h> using namespace std; class echo_server { public: echo_server() : port_(12345), host_("localhost") {} virtual ~echo_server() {} void start_server(); private: int port_; string host_; int sock_; struct sockaddr_in sin_; void init_server(); void create_socket(); void set_socket_address(); void start_bind(); void wait_access(); }; void *echo_back(void *data); void echo_server::start_server() { cout << "server[port = " << port_ << " : host = " << host_ << "]" << endl; init_server(); wait_access(); } void echo_server::init_server() { create_socket(); set_socket_address(); start_bind(); } void echo_server::wait_access() { while (true) { pthread_t th; int *con = new int[1]; *con = accept(sock_, NULL, 0); assert(*con != -1); assert(pthread_create(&th, NULL, &echo_back, (void *) con) == 0); pthread_join(th, NULL); } close(sock_); } void *echo_back(void *data) { char buf[32]; char tmp[64]; int len; int sock = static_cast<int>(*static_cast<int *>(data)); delete static_cast<int *>(data); // while (true) { memset(buf, 0x0, sizeof(buf)); memset(tmp, 0x0, sizeof(tmp)); len = recv(sock, tmp, sizeof(tmp), 0); assert(len != -1); strcpy(buf, tmp); send(sock, buf, len, 0); // } close(sock); return NULL; } void echo_server::create_socket() { sock_ = socket(AF_INET, SOCK_STREAM, 0); assert(sock_ != -1); } void echo_server::set_socket_address() { int opt_val = 1; memset(&sin_, 0x0, sizeof(sin_)); sin_.sin_family = AF_INET; sin_.sin_addr.s_addr = htonl(INADDR_ANY); sin_.sin_port = htons(port_); assert(setsockopt(sock_, SOL_SOCKET, SO_REUSEADDR, &opt_val, sizeof(opt_val)) != -1); } void echo_server::start_bind() { assert(bind(sock_, (struct sockaddr *) &sin_, sizeof(sin_)) != -1); assert(listen(sock_, SOMAXCONN) != -1); } int main(int argc, char **argv) { echo_server server; server.start_server(); return 0; }
やってることはユーザの入力をエコーバックするだけのエコーサーバです。
Makefileはこちら。
CC=g++ CFLAGS = -Wall CFLAGS += -O2 CFLAGS += -g LDFLAGS = -lpthread target = echo-server objs = echo-server.o all: $(objs) $(CC) $(LDFLAGS) $(objs) -o $(target) .c.o: $(CC) $(CFLAGS) -c $< clean: -rm -fr core* *~ *.o $(target)
それでmakeしてtelnetで実行するとこんな感じに。
[masami@moon:~/build/echo-server]% make g++ -c -o echo-server.o echo-server.cc g++ -lpthread echo-server.o -o echo-server [masami@moon:~/build/echo-server]% ./echo-server& server[port = 12345 : host = localhost] [1] 7232 [masami@moon:~/build/echo-server]% telnet localhost 12345 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. hello <- 入力した文字列 hello <- サーバからの出力 ^] telnet> quit Connection closed. [masami@moon:~/build/echo-server]%
SPIKEで使うのは単純な文字列の入力だけで良いから、こんな感じで。。
[masami@moon:~/tool/.../SPIKE/src]% cat echo_server.spk s_string_variable("hello"); [masami@moon:~/tool/.../SPIKE/src]%
最初にサーバを起動してからSPIKEを動かすと・・・
[masami@moon:~/build/echo-server]% gdb -q echo-server gdb $ r [Thread debugging using libthread_db enabled] server[port = 12345 : host = localhost] [New Thread 0x7f3d24cec6f0 (LWP 7325)] [New Thread 0x40c71950 (LWP 7329)] [Thread 0x40c71950 (LWP 7329) exited] [New Thread 0x40c71950 (LWP 7330)] warning: Can't attach LWP 1094795585: No such process zsh: abort (core dumped) gdb -q echo-server [masami@moon:~/build/echo-server]%
[masami@moon:~/tool/.../SPIKE/src]% LD_LIBRARY_PATH=. ./line_send_tcp localhost 12345 echo_server.spk 0 0 Total Number of Strings is 681 Fuzzing Fuzzing Variable 0:0 Read first line Fuzzing Variable 0:1 Read first line Variablesize= 5004 Fuzzing Variable 0:2 Couldn't tcp connect to target zsh: bus error (core dumped) LD_LIBRARY_PATH=. ./line_send_tcp localhost 12345 echo_server.spk 0 0
そうすると、こんな感じでサーバが落ちるのでSPIKEもサーバにアクセス出来ずに落ちてます。
coreをgdbで見るとこんな感じに。。。
gdb $ q [masami@moon:~/build/echo-server]% gdb -q ./echo-server -c core.7325 〜中略〜 Core was generated by `/home/masami/build/echo-server/echo-server'. Program terminated with signal 11, Segmentation fault. [New process 7330] [New process 7325] #0 0x00007f3d23e55b4e in strcpy () from /lib/libc.so.6 gdb $ bt #0 0x00007f3d23e55b4e in strcpy () from /lib/libc.so.6 #1 0x0000000000401348 in echo_back () #2 0x4141414141414141 in ?? () #3 0x414141412f3a2e2f in ?? () #4 0x4141414141414141 in ?? () #5 0x4141414141414141 in ?? () #6 0x4141414141414141 in ?? () #7 0x4141414141414141 in ?? () #8 0x4141414141414141 in ?? () #9 0x4141414141414141 in ?? () #10 0x4141414141414141 in ?? () #11 0x414141412f3a2e2f in ?? () #12 0x4141414141414141 in ?? () 〜中略〜 #467 0x414141412f3a2e2f in ?? () #468 0x4141414141414141 in ?? () #469 0x4141414141414141 in ?? () #470 0x4141414141414141 in ?? () #471 0x4141414141414141 in ?? () #472 0x4141414141414141 in ?? () #473 0x4141414141414141 in ?? () #474 0x4141414141414141 in ?? () Cannot access memory at address 0x40c72000 gdb $