Heap에서 발생할 수 있는 취약점에 대해 간단하게 내맘대로 정리해보자


1. Heap overflow

-    Heap 영역에 할당된 공간보다 큰 사이즈를 입력받아 발생할 수 있음

-    발생 예제

buf = malloc(100)

...

int size;

scanf("%d", &size);

read(0, buf, size);


-    활용방법

다음 chunk의 헤더 부분을 덮을 수 있는 경우, prev, next pointer를 조작해 free 시 임의 메모리 쓰기 발생 시킬 수 있음

(free 메커니즘에 의존, 제한적)


2.  Double free 

- heap overflow와 나누기 이상하기는 하지만 활용에 있어서 다르기 때문에 나눔

- 기본적으로 heap overflow 취약점을 가져야 함

- 활용방법

Heap chunk 헤더 내의 flag(정확히 표현하면 현재 chunk size의 하위 3비트) 값을 조작함으로써 할당된 chunk를 free된 것으로 인식하게 함

조작된 chunk 이전의 chunk가 free될 시 병합과정에서 위 1.과 유사하게 임의 메모리 쓰기 가능



3. fastbin dup into stack

-    참고(http://www.blackhat.com/presentations/bh-usa-07/Ferguson/Whitepaper/bh-usa-07-ferguson-WP.pdf)

-    allocation된 chunk를 free하면 재사용을 위해 free된 chunk를 linked list로 관리하고 이를 bin이라고 함

-    chunk의 사이즈가 작을 경우(기본 최대 60바이트, 설정하면 최대 80바이트) fastbin 이라는 free list를 통해 관리되며 다음과 같은 특징을 가짐

sorting이 되지 않음

singly linked list

LIFO

-    아무튼 작은 사이즈의 chunk를 할당하고 free 하는 경우



4. The house of force

-    Heap overflow를 이용해 top chunk를 덮음

-    이를 통해 할당할 수 있는 chunk size의 제한이 없어짐


5. Use after free(UAF)

-    free된 메모리 공간의 포인터에 접근할 수 있는 경우


나중에 내용 더 추가하자

'Pwnable.kr' 카테고리의 다른 글

pwnable.kr 문제풀이 현황  (0) 2018.05.12


pwnable.kr AEG 문제를 보던 중 푸는데에 ANGR을 사용해보면 좋을 것 같아 이 참에 찾아보았다.

구글링 등 예제 코드를 보고 내가 대충 작성한 코드는 다음과 같았는데

(문제 바이너리를 local 로 다운로드 받았다고 치고 시작)


mine.py 

 def main():

        proj = angr.Project('newbin0', load_options={"auto_load_libs": False})


        input_size = 0x60

        argv1 = claripy.BVS("argv1",input_size * 8)


        init = proj.factory.entry_state(args=["./newbin0", argv1])

        init.libc.buf_symbolic_bytes=input_size + 1

        al = [0x947C86,0x947976,0x9478FB,0x947889,0x947809,0x94778C,0x94770C,0x94768C,0x947610,0x9475A8,0x94752B,0x9474A9,0x94742C,0x9473B3,0x947337,0x9472BB,0x94723B]


        for byte in argv1.chop(8):

                init.add_constraints(byte >= '0')

                init.add_constraints(byte <= 'Z')

                init.add_constraints(byte != '\x3a')

                init.add_constraints(byte != '\x3b')

                init.add_constraints(byte != '\x3c')

                init.add_constraints(byte != '\x3d')

                init.add_constraints(byte != '\x3e')

                init.add_constraints(byte != '\x3f')

                init.add_constraints(byte != '\x40')


        init_path = proj.factory.path(init)

        path_group = proj.factory.path_group(init)

        path_group.explore(find=FIND_ADDR, avoid=al)


        found = path_group.found[0]

        solution = found.state.se.any_str(argv1)

        return solution



위와 같이 코드를 작성하고 실행할 경우 문제는 원하는 방향으로 풀리고 Hex 값을 return 해주지만 실행시간이 약 60초 걸렸다.

문제에서 주어진 시간은 10초로 angr 돌리는데에만 터무니없이 긴 시간이 걸렸음.

시간을 줄이기 위해 avoid 조건을 이용해 이것 저것 넣어봤는데 효과는 미비했다.


구글링 중 github에 aeg 문제풀이 코드가 나와있는 것을 찾았고 여기서 angr 부분만 참고했다.

(출처 : https://github.com/rot256/Wargames/blob/master/pwnable/aeg/attack.py)

원본 코드는 위 URL에서 확인할 수 있으며 밑에는 테스트에 필요한 코드만 추출, 조작함


attack.py

# Create symbolic buffer

p = angr.Project(tar)

buf = claripy.BVS("buf",48*8)

start_state = p.factory.blank_state(addr=0x2233b96)

start_state.memory.store(0x2436160, buf)


# Setup a stack frame

start_state.regs.rbp = start_state.regs.rsp

start_state.regs.rsp = start_state.regs.rsp - 0x50

start_state.memory.store(start_state.regs.rsp, start_state.se.BVV(0, 8*0x32))


# Setup stepper

pg = p.factory.path_group(start_state)

def step_func(pg):

    pg.drop(filter_func = lambda path: path.addr == 0x2233bbd)

    pg.stash(filter_func = lambda path: path.addr == 0x4006e0, from_stash='active', to_stash='found')

    return pg

pg.step(step_func = step_func, until = lambda pg: len(pg.found) > 0)

f = pr.found[0]

cert = f.state.se.any_str(buf)

print cert.encode('hex')


위 스크립트 실행 시 약 6-7s 정도 시간 소요로 답을 구할 수 있었다.


결국 차이점은

1) 적절한 바이너리의 start state 설정

2) avoid 조건

으로 필요한 연산만 하도록해 state를 줄여줄 수 있는 것으로 보인다.


조금 더 공부해봅시다.

'Pwnable.kr > Grotesque' 카테고리의 다른 글

[pwnable.kr] dos4fun - 444pt  (5) 2018.03.14
[pwnable.kr] sudoku - 111pt  (0) 2018.02.19
[pwnable.kr] AEG - 550pt  (0) 2018.02.11
[pwnable.kr] maze - 150pt  (0) 2017.12.23


* 펀드란

불특정 다수인으로부터 모금한 실적 배당형 투자 기금.[1] 주식, 채권, 파생상품 등에 대한 투자를 위해 고객들로부터 돈을 모아서 구성하는 일정 금액의 자금 운용 단위를 가리킨다



* Pros

-    투자의 수익금을 수익이 나는 만큼 투자자에게 돌려준다.

     즉 예, 적금보다 높은 수익률을 기대할 수 있음.

-    전문가를 통해 투자하므로 직접투자에 비해 안전(?)하다고 볼 수 있음

-    소액, 분산 투자가 가능하다


* Cons

-    펀드는 예금과 달리 예금자보호법(1인당 5,000만원 한도 보장)의 보호를 받을 수 없음

     펀드 운용구조를 통해 투자자의 자금을 보호하는 방식을 사용



* 펀드 종류

투자 대상에 따라 나눠보면 다음과 같다

-    증권펀드    - 주식형 : 주식에 60% 이상 투자

   - 혼합형    - 주식혼합형펀드 : 주식에 50% 이상 투자

 - 채권혼합형펀드 : 채권에 50% 이상 투자

   - 채권형 : 채권에 60% 이상 투자

-    부동산펀드

-    실물펀드

-    기타 등등.



* 펀드 종류 상세

-    투자금 납입방식에 따라 : 적립식, 거치식

-    지역에 따라 : 국내, 해외(국내법에 의해 만들어졌다면 역내펀드, 외국법에 의해 만들어졌다면 역외펀드)

-    스타일에 따라 : 배당형, 가치형, 성장형, 인덱스형(지수에 따라), 전환형(2개 펀드간 전환이 가능), 엄브렐러형(3개 펀드간 전환이 가능)

-    펀드자금 모집방법에 따라 : 공모형, 사모형

-    세제혜택에 따라 : 절세형, 소득공제형

-    투자자금 회수방법에 따라 : 개방형, 폐쇄형

-    추가가입 여부에 따라 : 추가형, 단위형



* 증권펀드 상세

-    대부분의 사람들이 투자하는 펀드의 종류

-    주식 비율이 높을 수록 고수익, 고위험의 특성을 가짐

-    주식형 펀드는 운용전략에 따라

ㅇ 배당형 : 배당을 많이 주는 주식에 투자(주가 등락에 신경쓰고 싶지 않다면 선택)

ㅇ 가치형 : 실제 기업 가치보다 저평가된 주식에 주로 투자(상동)

ㅇ 성장형 : 성장이 예상되는 산업에 주로 투자(주가 등락에 민감하게 반응하는 스타일이 선택하면 좋음)

-    채권에 대한 고려사항

ㅇ 단기채권, 장기채권을 확인할 것, 장기채권은 금리 변동에 민감할 수 있음

ㅇ 채권 종류와 신용등급을 확인할 것(펀드 평가회사 ex. 제로인, 모닝스타코리아 확인)



* 펀드 규모에 따라

-    100억 미만이면 소형

-    100~1,000억이면 중형

-    1,000억 이상이면 대형

-    5,000억 이상이면 초대형

-    규모가 작을수록 발빠른 대응이 가능하나 상대적으로 보수가 적어 자산운용회사 관리가 소홀할 우려가 있음

-    규모가 클수록 분산투자 운용에 유리하지만 변화에 탄력적 대응이 어려움



* 펀드 투자 advice

-    환매, 손절매에 대한 원칙을 세우고 지켜라

-    초심자라면 적립식 펀드로 중형 이상의 펀드로 시도해보는 것이 좋다

-    채권형 펀드에 분산투자 하는것으로 시작해보자

-    분산 노하우

ㅇ 적립식 펀드로

ㅇ 지역 분산, 국내, 해외

ㅇ 대상 분산, 주식, 혼합, 채권



* 펀드 운용 구조

[투자자]    -    [판매회사]    -    [수탁회사]

|                        |

- [자산운용회사] ---



* 판매회사 평가 참고

-    금융감독원 홈페이지(www.fss.or.kr) 상단 보도홍보 - 보도자료 - 미스터리 검색 - 펀드 미스테리 쇼핑 결과 확인 가능

-    한국금융투자자보호재단의 평가결과도 참고 가능

-    직접 상품비교해보는것도 좋다



* 펀드 비용의 종류

-    수수료

ㅇ 선취 판매 수수료 : 펀드 가입시 내는 비용

ㅇ 후취 판매 수수료 : 펀드 환매 시 내는 비용(선취, 후취 선택)

ㅇ 환매 수수료 : 펀드 환매를 너무 일찍(보통 3개월이내) 할 때 내는 비용

-    보수

ㅇ 판매보수 : 판매회사에 내는 보수

ㅇ 운용보수 : 자산운용회사에

ㅇ 수탁보수 : 수탁회사에



* 수수료 보수 절약법

-    총 비용이 낮은 펀드 선택 : 운용보수보다 판매보수가 낮은 펀드를 선태갛는 것이 유리

-    창구 가입보다 인터넷가입이 수수료에 유리

-    펀드의 클래스 확인 : 2년 이상 중장기에는 클래스A, 2년 이내 단기적 투자에는 클래스C 가 좋음



* 펀드 이름을 보고 파악하기

대신 / 성장중소형주 / 증권 / 투자신탁 / [주식] / ClassA

  1              2            3          4           5          6

1    자산운용사 : 펀드를 관리하고 운용하는 회사

2    스타일(운용전략)

3    운용자산

4    법적속성

5    운용대상

6    판매수수료

Motivation

pwnable.kr AEG 문제를 풀던 중 angr을 사용해보면 좋을 것 같아 슬쩍 훑어보고 코드만 가져다쓰려고 했는데 역시나 생각보다 어렵고 내용이 많아... 한번 공부해보면 좋을 것 같아 쓰게 됨


작성

https://docs.angr.io/ 내용 기반으로, 주관적으로 중요해보이는 내용 위주로 정리함

혹시 참고하시는 분들은 오역에 주의





Top Level Interfaces

Angr 에서는 project가 분석의 프레임으로 사용된다.

Project에는 기본적으로 다음과 같은 속성들이 있다.


>>> import monkeyhex # this will format numerical results in hexadecimal
>>> proj.arch
<Arch AMD64 (LE)>
>>> proj.entry
0x401670
>>> proj.filename
'/bin/true'

Angr에선 바이너리에서 가상메모리로 맵핑시키기 위해 CLE 모듈을 사용하는데 모듈의 결과값을 .loader 를 이용해 사용할 수 있다.


>>> proj.loader
<Loaded true, maps [0x400000:0x5004000]>
>>> proj.loader.shared_objects # may look a little different for you!
{'ld-linux-x86-64.so.2': <ELF Object ld-2.24.so, maps [0x2000000:0x2227167]>,
 'libc.so.6': <ELF Object libc-2.24.so, maps [0x1000000:0x13c699f]>}

>>> proj.loader.min_addr
0x400000
>>> proj.loader.max_addr
0x5004000

Angr에서 다양한 다수개 클래스들의 사용 편의를 위해 project.factory 생성자를 제공함

이를 이용해 간편히 자주 사용하는 클래스에 접근 가능하다.


Block - 입력받은 주소의 basic block을 추출

>>> block = proj.factory.block(proj.entry) # lift a block of code from the program's entry point
<Block for 0x401670, 42 bytes>

>>> block.pp()                          # pretty-print a disassembly to stdout
0x401670:       xor     ebp, ebp
0x401672:       mov     r9, rdx
0x401675:       pop     rsi
0x401676:       mov     rdx, rsp
0x401679:       and     rsp, 0xfffffffffffffff0
0x40167d:       push    rax
0x40167e:       push    rsp
0x40167f:       lea     r8, [rip + 0x2e2a]
0x401686:       lea     rcx, [rip + 0x2db3]
0x40168d:       lea     rdi, [rip - 0xd4]
0x401694:       call    qword ptr [rip + 0x205866]

>>> block.instructions                  # how many instructions are there?
0xb
>>> block.instruction_addrs             # what are the addresses of the instructions?
[0x401670, 0x401672, 0x401675, 0x401676, 0x401679, 0x40167d, 0x40167e, 0x40167f, 0x401686, 0x40168d, 0x401694]

SimState - Project 객체는 단순히 프로그램의 초기 이미지이므로 사용자가 angr을 이용 시 시뮬레이팅할 특정 조건을 정의해줘야 한다.

>>> state = proj.factory.entry_state()
<SimState @ 0x401670>

SimState는 메모리, 레지스터, 파일시스템 데이터 등 실행 시 상태에 따라 변경될 수 있는 값들을 포함한다.

사용자는 state.regs, state.mem 등 코드를 통해 사용 가능하다.

>>> state.regs.rip        # get the current instruction pointer
<BV64 0x401670>
>>> state.regs.rax
<BV64 0x1c>
>>> state.mem[proj.entry].int.resolved  # interpret the memory at the entry point as a C int
<BV32 0x8949ed31>

위 값들을 살펴보면 단순한 정수값이 아닌 bitvector임을 알 수 있는데 상세한 내용은 뒤에서 알아보자.

bitvector와 파이썬 정수형과 변환 예제는 다음과 같다.

>>> state.regs.rsi = state.solver.BVV(3, 64)
>>> state.regs.rsi
<BV64 0x3>
>>> state.mem[0x1000].long = 4
>>> state.mem[0x1000].long.resolved
<BV64 0x4>



Simulation Managers - Simulation Manager는 Angr에서 state 정보를 포함해 프로그램을 실행, 시뮬레이션하는 인터페이스다.

예를 들어 살펴보자. 먼저 사용할 simulation manager를 생성한다. 

>>> simgr = proj.factory.simulation_manager(state)
<SimulationManager with 1 active>
>>> simgr.active
[<SimState @ 0x401670>]

simulation manager는 state들의 stash 값을 가지는데, active가 기본값이다.

다음 명령을 통해 symbolic execution의 basic block을 실행할 수 있는데 실행에 따른 값 변화 시 원본 state의 값을 수정하는 것이 아닌 다수개의 state로 저장하는 것이다.

>>> simgr.step()
>>> simgr.active
[<SimState @ 0x1020300>]
>>> simgr.active[0].regs.rip                 # new and exciting!
<BV64 0x1020300>
>>> state.regs.rip                           # still the same!
<BV64 0x401670>


분석도구 - angr은 몇 개의 built-in 분석 도구를 포함하고 있으며 이를 사용자 펀의에 따라 사용 가능하다.


>>> proj.analyses.            # Press TAB here in ipython to get an autocomplete-listing of everything:
 proj.analyses.BackwardSlice        proj.analyses.CongruencyCheck      proj.analyses.reload_analyses       
 proj.analyses.BinaryOptimizer      proj.analyses.DDG                  proj.analyses.StaticHooker          
 proj.analyses.BinDiff              proj.analyses.DFG                  proj.analyses.VariableRecovery      
 proj.analyses.BoyScout             proj.analyses.Disassembly          proj.analyses.VariableRecoveryFast  
 proj.analyses.CDG                  proj.analyses.GirlScout            proj.analyses.Veritesting           
 proj.analyses.CFG                  proj.analyses.Identifier           proj.analyses.VFG                   
 proj.analyses.CFGAccurate          proj.analyses.LoopFinder           proj.analyses.VSA_DDG               
 proj.analyses.CFGFast              proj.analyses.Reassembler

상세 내용은 아래 URL의 api documentation에서 사용 가능하다.

(http://angr.io/api-doc/angr.html?highlight=cfg#module-angr.analysis)





바이너리 로딩 - CLE와 angr Projects


Loader 사용

>>> import angr, monkeyhex
>>> proj = angr.Project('/bin/true')
>>> proj.loader
<Loaded true, maps [0x400000:0x5008000]>


Loader 객체

cle.loader는 단일 메모리 공간에 맵핑된 바이너리 객체의 집합이다. 각 바이너리 객체는 loader의 백엔드를 이용해 로딩되고 파일 타입을 이용해 다룰 수 있다(ex. cle.ELF)

>>> proj.loader.all_objects
[<ELF Object fauxware, maps [0x400000:0x60105f]>,
 <ELF Object libc.so.6, maps [0x1000000:0x13c42bf]>,
 <ELF Object ld-linux-x86-64.so.2, maps [0x2000000:0x22241c7]>,
 <ELFTLSObject Object cle##tls, maps [0x3000000:0x300d010]>,
 <KernelObject Object cle##kernel, maps [0x4000000:0x4008000]>,
 <ExternObject Object cle##externs, maps [0x5000000:0x5008000]>

# This is the "main" object, the one that you directly specified when loading the project
>>> proj.loader.main_object
<ELF Object true, maps [0x400000:0x60105f]>

# This is a dictionary mapping from shared object name to object
>>> proj.loader.shared_objects
{ 'libc.so.6': <ELF Object libc.so.6, maps [0x1000000:0x13c42bf]>
  'ld-linux-x86-64.so.2': <ELF Object ld-linux-x86-64.so.2, maps [0x2000000:0x22241c7]>}

# Here's all the objects that were loaded from ELF files
# If this were a windows program we'd use all_pe_objects!
>>> proj.loader.all_elf_objects
[<ELF Object true, maps [0x400000:0x60105f]>,
 <ELF Object libc.so.6, maps [0x1000000:0x13c42bf]>,
 <ELF Object ld-linux-x86-64.so.2, maps [0x2000000:0x22241c7]>]

# Here's the "externs object", which we use to provide addresses for unresolved imports and angr internals
>>> proj.loader.extern_object
<ExternObject Object cle##externs, maps [0x5000000:0x5008000]>

# This object is used to provide addresses for emulated syscalls
>>> proj.loader.kernel_object
<KernelObject Object cle##kernel, maps [0x4000000:0x4008000]>

# Finally, you can to get a reference to an object given an address in it
>>> proj.loader.find_object_containing(0x400000)
<ELF Object true, maps [0x400000:0x60105f]>

다음과 같이 객체를 이용해 바로 데이터 획득도 가능하다

>>> obj = proj.loader.main_object

# The entry point of the object
>>> obj.entry
0x400580

>>> obj.min_addr, obj.max_addr
(0x400000, 0x60105f)

# Retrieve this ELF's segments and sections
>>> obj.segments
<Regions: [<ELFSegment offset=0x0, flags=0x5, filesize=0xa74, vaddr=0x400000, memsize=0xa74>,
           <ELFSegment offset=0xe28, flags=0x6, filesize=0x228, vaddr=0x600e28, memsize=0x238>]>
>>> obj.sections
<Regions: [<Unnamed | offset 0x0, vaddr 0x0, size 0x0>,
           <.interp | offset 0x238, vaddr 0x400238, size 0x1c>,
           <.note.ABI-tag | offset 0x254, vaddr 0x400254, size 0x20>,
            ...etc

# You can get an individual segment or section by an address it contains:
>>> obj.find_segment_containing(obj.entry)
<ELFSegment offset=0x0, flags=0x5, filesize=0xa74, vaddr=0x400000, memsize=0xa74>
>>> obj.find_section_containing(obj.entry)
<.text | offset 0x580, vaddr 0x400580, size 0x338>

# Get the address of the PLT stub for a symbol
>>> addr = obj.plt['abort']
>>> addr
0x400540
>>> obj.reverse_plt[addr]
'abort'

# Show the prelinked base of the object and the location it was actually mapped into memory by CLE
>>> obj.linked_base
0x400000
>>> obj.mapped_base
0x400000


Symbols and Relocations

CLE의 loader.find_symbol 을 이용해 심볼 정보를 확인할 수 있으며 심볼 이름과 주소 모두 이용 가능하다

>>> malloc = proj.loader.find_symbol('malloc')
>>> malloc
<Symbol "malloc" in libc.so.6 at 0x1054400>


바이너리 로딩 옵션

바이너리 옵션 - 특정 바이너리 객체를 로딩할때 옵션을 정의하고 싶으면 사용 가능하다

* backend - 사용할 백엔드 지정(ex. elf, pe, mach-o...)

* custom_base_addr - 사용할 베이스 어드레스 주소

* custom_entry_point - 사용할 엔트리 포인트

* custom_arch - 사용할 아키텍쳐














'Fuzzing & Binary analysis' 카테고리의 다른 글

Angr 설치 및 실행  (0) 2017.12.27


Python virtualenvwrapper 설치, 환경설정

# pip install virtualenvwrapper

# vi ~/.bashrc


export WORKON_HOME=$HOME/.virtualenvs

source /usr/local/bin/virtualenvwrapper.sh


# source ~/.bashrc



Pypy 설치

http://pypy.org/download.html 에서 환경에 맞춰 다운로드, 압축해제



Angr-dev 설치(출처 : http://kshmk.tistory.com/92)

# mkvirtualenv -p /opt/pypy/bin/pypy angr

# deactivate

# git clone https://github.com/angr/angr-dev

# cd angr-dev

# setsid sh -c 'tty; ps -jp "$$"; ./setup.sh -i -p angr' < /dev/null  // github id, pw 물어봐서 이 옵션 사용


# workon angr



Example code  실행

Angr 프로젝트에 예제로 들어 있는 바이너리를 분석해보자


실행 코드

import angr


project = angr.Project("angr-dev/angr-doc/examples/defcamp_r100/r100", auto_load_libs=False)


@project.hook(0x400844)

def print_flag(state):

    print "FLAG SHOULD BE:", state.posix.dump_fd(0)

    project.terminate_execution()


project.execute() 


실행 결과

(angr) root@ubuntu:/home/u64/angr# python test.py 

WARNING | 2017-12-27 04:46:07,890 | angr.analyses.disassembly_utils | Your verison of capstone does not support MIPS instruction groups.

FLAG SHOULD BE: Code_Talkers


'Fuzzing & Binary analysis' 카테고리의 다른 글

[작성중] Angr docs를 공부해보자  (0) 2018.01.04

최근 pwnable.kr Grotesque 문제들이 너무 어려워서 스트레스... 였는데 간만에 재밌게 풀었습니다.


취약점은 리버싱해보면 비교적 쉽게 발견할 수 있고, 바이너리 내에 system(/bin/sh) 함수도 있으니 취약점까지 가는 길만 찾으면 되겠습니다

'Pwnable.kr > Grotesque' 카테고리의 다른 글

[pwnable.kr] dos4fun - 444pt  (5) 2018.03.14
[pwnable.kr] sudoku - 111pt  (0) 2018.02.19
[pwnable.kr] AEG - 550pt  (0) 2018.02.11
ANGR로 AEG를 풀어보자  (0) 2018.01.25

정규표현식이란


정규 표현식(正規表現式, 영어: regular expression, 간단히 regexp[1] 또는 regex, rational expression)[2][3] 또는 정규식(正規式)은 특정한 규칙을 가진 문자열의 집합을 표현하는 데 사용하는 형식 언어이다.




메타 문자 정리


문자클래스 [] 

- [ 와 ] 사이 문자들의 매치

- [ ] 내의 ^ : 다음 문자를 제외 (ex) [^p].

- [ ] 내의 - : 범위 표현  (ex) [a-z]

- \d : 숫자,   \w : 숫자+영문자,   \s : 공백문자, 대문자의 경우 반대


. (Dot)

- \n을 제외한 모든 문자와 매치


*

- 반복, 0부터 무한개까지 매칭


+

- 반복, 1부터 무한개까지 매칭


?

- 반복, 0부터 1개까지 매칭


{m,n}

- 반복, m개 이상, n개 이하개 매칭

- 즉,   * == {0,}    + == {1,}      ? == {0,1}


^

- 문자열 시작문자와 매칭 (ex) ^p


$

- 문자열 마지막 문자와 매칭 (ex) ;$

- . $ ^ 을 문자열로 사용하고 싶으면 [] 안에 넣어 사용하면 됨 


( )

- 그룹핑에 사용

- group(0) : 매칭된 전체 문자열,   group(n) : n번째 그룹




정규표현식 테스트 사이트


https://regexr.com/


참고 : https://wikidocs.net/4309

'관련TIP' 카테고리의 다른 글

커널 모듈의 관리  (0) 2018.02.07
라이브러리 .a 파일 .so 파일  (0) 2017.04.28
프로그램 분석




이번 문제는 바이너리 없이 client, host 에서 돌고 있는 파이썬 스크립트를 주어지는데
주어진 스크립트에는 중요 변수 내용(iv, key, cookie) 값이 없는 상태이다.



주요 코드를 살펴보면  client에선 ID, PW, COOKIE 값을 (ID-PW-COOKIE)를 암호화한 값을 전송하며
서버에선 이 값을 복호화해 - 를 기준으로 split해 값을 판별하는 것을 알 수 있다.




취약점 탐색

이번 문제를 보면서 역시나 시스템적인 취약점이 있지 않을까? 하면서 여기 저기 값을 "A"*100.... 넣어봤는데 취약점은 발동하지 않았다.

문제의 의도대로 AES - CBC 암호화에 대해 알아야 풀 수 있는 것 같아 암호화 알고리즘에 대해 공부했다.
참고 자료에서 보면 자세히 알 수 있지만 간단히 말하자면
plain text를 block size 에 따라 나눠 암호화하고, plain text (xor) initial vector 한 값을 암호화해 나온 암호화 block 값을 다음 암호화에 사용하는 게 핵심적인 내용이다.

여기서 중요한 것은 plain text를 block size로 나눠 암호화 하며, 첫 번째 block은 initial vector 값에 의존해 암호화되어 결과값이 나온다는 것 2가지이다.



위 코드에서 보듯, block size는 16byte 이므로 16byte씩 끊어서 암호화를 진행하게 된다

이 때 위의 그림을 보면 id, pw, cookie 값을 - 문자를 기준으로 split 하는 것이 중요한 취약점이 될 수 있다.

사용자의 입력을 받는 id, pw 같은 경우 - 문자가 들어갈 수 있으므로 (입력 가능한 문자 아래 그림 참조)




사용자가 만약 id를 a-b-c- 로 입력 시 프로그램은 a를 ID, b를 PW, C를 COOKIE 값으로 판별하게 된다.

즉 사용자의 의도대로 ID, PW, COOKIE 값을 변조할 수 있는 것인데 서버 프로그램의 코드를 살펴보면



사용자가 전송한 COOKIE값이 일치하지 않을 경우 0을 return해 인증되지 않은 사용자라는 출력을 해주고 프로그램은 종료된다.
결국 COOKIE 값을 맞춘 후, hash값만 일치시키면 admin 사용자로 인증할 수 있게 된다.



COOKIE 값을 구하기 위한 Idea 고찰

cookie값은 어떤 값, 방식을 통해 구할수 있을까? 고민하다가 

우선 id, pw, cookie 값이 - 로 구분되는 것첫 번째 암호화된 block의 변수는 plain block1 값과 iv 값 두 가지 인것을 이용하기로 했다.

즉 iv의 값이 고정일 경우 plain block1 의 값이 변해야 encyrpted block1 의 값이 변하는 것이므로 다음과 같은 아이디어를 생각했다.


ID : '-' * 12, PW : '-' 를 입력한다면 ?

암호화 되기 전 평문은  ---------------COOKIEVALUE.... 이런식으로 구성 될텐데 이 때 블럭 사이즈가 16 이므로 

---------------C |  OOKIEVALUE...... | ......
   block 1.              block 2.             block 3 ....

위 평문을 암호화한 암호문의 첫번째 블락의 값을 구하면 ---------------C, 즉 쿠키의 첫번째 글자를 포함한 암호화 값을 알 수 있다.



또 우리는 ID, PW에 '-' 문자를 포함할 수 있으므로 

ID : '-'*15 + ?      , PW : anything

위 물음표 자리에 문자열을 하나씩 대입해 나오는 암호문의 첫번째 블락 값을 위 쿠키의 첫번째 글자를 포함한 암호화 값비교하면

쿠키의 첫번째 글자의 값을 알 수 있다.

이와 같이 한글자씩 쿠키의 값을 알아낼 수 있다.



COOKIE 값 구하는 코드

코드 돌리면서도 계속 헷갈려서 자동화는 안하고 손으로 맞춰보면서 돌렸다.
한마디로 발로 짜서 개판인 코드 허허...

from pwn import *


context(arch = 'amd64', os = 'linux')

local=False


# first  

p = remote("pwnable.kr", 9006)


print p.recvuntil('ID\n')

p.sendline('-'*12)

print p.recvuntil('PW\n')

p.sendline('-')

data = p.recvuntil('user\n')

enc = data[data.index('(')+1:data.index(')')]

print len(enc)


enc = enc[0:32]

print enc

print len(enc)


# brute

for i in '1234567890abcdefghijklmnopqrstuvwxyz-_ABCDEFGHIJKLMNOPQRSTUVWXYZ' :

        p = remote("pwnable.kr", 9006)

        p.recvuntil('ID\n')

        p.sendline('-'*15+i)

        p.recvuntil('PW\n')

        p.sendline('-')

        data = p.recvuntil('user\n')

        try_ = data[data.index('(')+1:data.index(')')]

        try_ = try_[0:32]

        if enc == try_ :

                print "FIND!! first one is " + i

                break

 

 




Flag 얻기

cookie값을 알았으므로 나머지는 간단히 처리할 수 있다.



위 코드를 보면 ID가 admin 이며, PW의 hash 값이 맞는 경우 서버로부터 2를 return 받고 flag 값을 알 수 있다. 

다음과 같이 'admin' + cookie 값의 hash 값을 구해서

print hashlib.sha256("admin"+COOKIE_VALUE).hexdigest()



ID :  admin-HASH_VALUE-COOKIE_VALUE
PW : anything

을 전송하면 정상적으로 flag 값을 확인 할 수 있다.








===============================================================================================



참고자료 1. (출처:https://wikidocs.net/64)


3.5. 축약함수(Lambda)

오늘은 람다 형식과 그것을 이용하는 여러가지 함수들에 대해서 알아보겠습니다. 당장 완벽하게 소화하실 필요는 없을 것 같구요, 가벼운 마음으로 이런 것이 있다는 정도만 아셔도 되지 않을까 합니다. 람다 형식은 인공지능 분야나 AutoCAD라는 설계 프로그램에서 쓰이는 Lisp 언어에서 물려받았다고 하는데요, 함수를 딱 한 줄만으로 만들게 해주는 훌륭한 녀석입니다. 사용할 때는 아래와 같이 써주면 되지요.

lambda 인자 : 표현식

다음은 두 수를 더하는 함수입니다.

>>> def hap(x, y):
...   return x + y
...
>>> hap(10, 20)
30

이것을 람다 형식으로는 어떻게 표현할까요?

>>> (lambda x,y: x + y)(10, 20)
30





참고자료 2. (https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_Block_Chaining_.28CBC.29)


암호 블록 체인 방식 (CBC)[편집]

암호 블록 체인 (cipher-block chaining, CBC) 방식은 1976년 IBM에 의해 개발되었다.[4] 각 블록은 암호화되기 전에 이전 블록의 암호화 결과와 XOR되며, 첫 블록의 경우에는 초기화 벡터가 사용된다. 초기화 벡터가 같은 경우 출력 결과가 항상 같기 때문에, 매 암호화마다 다른 초기화 벡터를 사용해야 한다.

Cbc encryption.png

Cbc decryption.png

CBC 방식은 현재 널리 사용되는 운용 방식 중 하나이다. CBC는 암호화 입력 값이 이전 결과에 의존하기 때문에 병렬화가 불가능하지만, 복호화의 경우 각 블록을 복호화한 다음 이전 암호화 블록과 XOR하여 복구할 수 있기 때문에 병렬화가 가능하다.



'Pwnable.kr > Rookiss' 카테고리의 다른 글

[pwnable.kr] loveletter - 50pt  (0) 2018.09.07
[pwnable.kr] brain fuck - 150pt  (0) 2017.04.16
[pwnable.kr] md5 calculator - 200pt  (0) 2017.01.02
[pwnable.kr] fsb - 20pt  (0) 2016.11.17
[pwnable.kr] echo2 - 50pt  (0) 2016.11.10





정적라이브러리

- 동적(공유)라이브러리에 비해 실행 속도가 빠르고 배포에 제약이 없음

- 다만, 해당 라이브러리를 필요로 하는 모든 경우 같은 정적 라이브러리가 링크되기 때문에 배포 파일들의 사이즈가 커짐

- 그러므로 하드디스크 공간도 더 차지하고 메모리도 더 많이 차지함

- 그러나 유닉스 시스템의 경우 그때그때 필요한 부분만 메모리에 로딩하는 demand paging을 사용하기 때문에 정적인 라이브러리의 메모리 사용률과 공유 라이브러리의 메모리 사용률의 차이가 크지 않음


시스템에서 응급시에 필수로 쓰이는 유틸리티와 실행속도를 극대화해야 하는 몇몇 서버를 제외하고는 대부분 동적 라이브러리를 사용한다.



*shared library와 dynamic link library는 다른 개념이다

그러나 대부분의 경우 dynamic link library는 shared library를 만들 때 사용됨



확장자별 라이브러리 종류

*.a: 리눅스/정적 라이브러리

*.so: 리눅스/동적라이브러리

*.lib: 윈도우/정적라이브러리

*.dll: 윈도우/동적라이브러리




정적 라이브러리를 가지고 동적라이브러리로 만들기

a파일(정적라이브러리)에서 o파일(오브젝트)을 뽑아낸 다음 ld로 so타겟으로 해서 만들면된다.

$ar x abc.a

 a.o, b.o, c.o

$gcc -shared -o abc.so *.o //다시 o를 lib로 묶는다



라이브러리와 헤더파일

1. 다르다.

라이브러리는 기계어로 번역된 라이브러리이고,

헤더파일은 컴파일 하기 전의 즉, 프로그래머가 이해할 수 있고 문법에 맞게 작성되어 있는 선언들의 집합이다.


헤더가 여러개 모이는 것 != 라이브러리

컴파일된 산물인 *.o(오브젝트)파일을 여러개 모아 놓은 것 == 라이브러리


라이브러리를 사용하기 위해서 해당 라이브러리의 헤더파일이 있어야한다. 링커가 알아먹을 수 있는 심볼네임을 가지고 라이브러리를 뒤져서 링크를 하게 된다.

컴파일러가 이런 헤더파일을 가지고 심볼네임을 만들어서 오브젝트 파일에 넣어주면 링커가 해당 심볼네임을 가지고 라이브러리를 뒤져서 링크를 하게 된다.



공유와 동적의 차이

- 두개의 차이를 특별히 나누지 않는다. 다만 동적lib를 공유방식으로 사용하느냐, 독립적으로 사용하느냐는 메모리에 load할 때 결정된다. 'man dlopen'참조



출처: http://ndlessrain.tistory.com/entry/라이브러리-a-파일-so-파일 [ndlessrain]

'관련TIP' 카테고리의 다른 글

커널 모듈의 관리  (0) 2018.02.07
정규표현식 정리  (0) 2017.12.23

문제 푸느라, 사실 삽질하느라 날아간 일요일을 기리며 허허...

주말저녁에 문제 풀고 writeup 쓰고 있는게 싱숭생숭하면서도 보람차네요(사실 풀고나면 별거 아니지만요)


======================================================


보호 기법 확인(checksec)




CANARY, NX 확인, 서버 환경 상 ASLR enable.




프로그램 동작 분석



x86 binary, 실행 시 사용자의 입력을 받고 프로그램 종료.

겉보기엔 모르니 리버싱을 해봅시다




바이너리 리버싱






main() 에서 사용자 입력을 받아 한 글자씩 파싱. do_brainfuck() 함수 내부에서 각 case에 알맞는 기능을 처리


여기서 p 변수를 살펴보면 main() 에서 p = &tape 로 초기화하고 이때 값은 0x804a0a0 .


이 함수에서 p 의 값을 이용해 ++, --, putchar ... 등등 처리를 해주므로 이것을 이용해 볼 수 있겠다.




Exploit 전략 구성


0x804a0a0 값을 기준으로 >, < 를 이용해 메모리 값을 변경할 수 있고 getchar(), putchar() 명령을 사용할 수 있다.


다만 BOF나 다른 취약점이 아니므로 stack을 마음대로 바꾸지 못하고, parameter로 넘어가는 값을 쉽게 조작할 수 없다.


system(/bin/sh) 를 실행하기 위해 어떻게 할까



- puts() 이용 ?



puts의 GOT를 system으로 덮어쓰고 "[ and ] not supported." 를 overwrite 하려고 했는데 당연하게도 위 string의 위치는 쓰기 권한 없음


위 영역에 어떻게 접근해서 써야하나 고민 많이 했는데 당연히 안됨. 실패.


- putchar() 이용 ?



위와 비슷하게 _putchar의 GOT를 system으로 덮고 파라미터로 넘어가는 ds:p를 조작해 /bin/sh string 주소를 넘김


하지만 넘기는 값이 byte ptr [eax] 이므로 메모리 주소가 정상적으로 넘어가지 않음.


코드를 좀더 꼼꼼히 봤어야 했는데.. 실패.



- setvbuf() 이용 !


main() , do_brainfuck() 에서 이용하는 함수 중 첫번째 parameter를 control할 수 있는 함수가 뭐가 있을까 살펴보다가 




setvbuf 호출 시 첫번째 parameter는 stdin 으로




해당 값은 bss 영역으로 Read/Write 권한이 있다.


이를 이용해 다음과 같이 system(/bin/sh) 을 위한 전략을 구상했다.


1 - setvbuf() GOT 를 system() 으로 overwrite. ( 문제에서 libc도 제공하므로 두 함수 사이의 offset 계산 가능 )

2 - stdin overwrite

0x804a040  :  0x804a044

0x804a044  :  /bin/sh\x00

3 - puts() GOT 를 main() 내 setvbuf() 호출하는 코드 주소로 overwrite ( 위의 경우는 0x80486b9 )

4 - '[' 입력으로 puts() 호출.


정상적으로 쉘 획득하는 것을 확인함.




공격 코드





'Pwnable.kr > Rookiss' 카테고리의 다른 글

[pwnable.kr] loveletter - 50pt  (0) 2018.09.07
[pwnable.kr] crypto1 - 120pt  (0) 2017.05.20
[pwnable.kr] md5 calculator - 200pt  (0) 2017.01.02
[pwnable.kr] fsb - 20pt  (0) 2016.11.17
[pwnable.kr] echo2 - 50pt  (0) 2016.11.10

+ Recent posts