SPIKE

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 $