상세 컨텐츠

본문 제목

[Exploit Tech] Return to dl resolve

SYSTEM HACKING/Exploit Tech

by koharin 2020. 2. 21. 09:03

본문

728x90
반응형

1. JMPREL, SYMTAB, STRTAB

 

각 JMPREL, SYMTAB, STRTAB 주소는 

 

$ readelf -a babystack | grep ""

 

로 구할 수 있다.

 

 

SYMTAB : 0x80481cc

JMPREL : 0x80482b0

STRTAB : 0x804822c

 

 

1) JMPREL

 

JMPREL segment (rel.plt) Relocation table이라는 테이블을 가지고있다.

각 엔트리는 symbols에 맵핑되어 있다.

 

 

이 엔트리들의 타입은 Elf32_Rel이다.

 

하나의 entry 크기는 8바이트이다.

테이블에서 하나의 엔트리를 살펴보자면,

Sym.Name : Symbols의 이름 : read@GLIBC_2.0

Offsetsymbol에 대한 GOT entry 주소 : 0x0804a00c

Info : ELF32_R_SYM ELF32_R_TYPE 같은 추가 metadata

 

정의된 MACROS 에 따르면,

ELF32_R_SYM(r_info) == 1

ELF32_R_TYPE(r_info) == 7 (R_386_JUMP_SLOT)

 

 

2) STRTAB

 

STRTABsymbols 이름에 대한 문자열을 저장하는 table이다.

 

 

3) SYMTAB

 

Symbol 정보를 가지고 있는 테이블.

entryElf32_Sym 구조체이고, 사이즈는 16바이트이다.

 

 st_name : STRTAB에 있는 offset을 준다. (symbol의 이름이 시작하는)

 

ELF32_R_SYM(r_info) == 1 변수는 SYMTAB에서 Elf32_Sym의 인덱스를 준다.

 

index는 ELF32_R_SYM(r_info)이다.

 

SYMTAB + index*sizeof(entry)

 

 

Elf32_sym의 처음 4바이트를 STRTAB에 더하면 symbol name의 주소를 구할 수 있다.

 


2. dl_runtime_resolve

 

jmp DWORD PTR ds: 0x804a00c

1) 프로그램은 0x804a00c에서 GOT 값을 읽고 PLT 섹션으로 점프한다.

 

push 0x0

2) 인자 0x0을 스택에 push

 

jmp 0x80482f0

3) 나머지 인자를 push하고 resolver로 점프한다.

 

 

위에는

 

_dl_runtime_resolve( link_map, rel_offset )

 

와 같은 과정이다.

 

rel_offset : JMPREL 테이블의 Elf32_Rel의 offset

Link_map(0x804a004) : 모든 로드된 라이브러리 리스트. _dl_runtime_resolve는 symbol을 resolve하는데 이 리스트를 사용한다.

 

_dl_runtime_resolve(link_map, rel_offset){
	Elf32_Rel *rel_entry = JMPREL + rel_offset;
    Elf32_Sym *sym_entry = &SYMTAB [ ELF32_R_SYM (rel_entry -> r_info )];
    char *sym_name = STRTAB + sym_entry -> st_name;
    _search_for_symbol_(link_map, sym_name);
    
    read(0, buf, 0x100);
}

 

JMPREL + rel_offset 은 특정함수의 elf_32_rel 구조체의 주소이다.

 


3. how to exploit

 

제어가능한 영역에 rel_entry같은 큰 rel_offset을 놓는다..?

 

system 함수 symbol을 bind할 _dl_runtme_resolve 를 할 Elf32_Rel과 Elf32_Sym 구조체를 만들어야 한다.

 

그리고 상응하는 pseudo-entry의 인덱스를 정확하게 계산해야 한다.

 

Elf32-Rel과 Elf32_Sym 구조체는 controllable 영역에 만들어야 한다.

 

그리고 resolver가 이 가짜 구조체를 읽을 수 있도록 rel_offset을 제공해야 한다.

 

1) _dl_runtime_resolve(link_map, 0x300) (0x300 : controllable area) 가 호출됐을 때 0x300 offset은

Elf32_Rel* rel = JMPREL + 0x300 == 0x300

을 구하기 위해 사용된다.

 

2) 0x304의 r_info 필드를 사용해서 Elf32_Sym에 접근하게 된다.

Elf32_Sym* sym = &SYMTAB[(0x2100 >> 8)] == 0310

 

3) symbol 문자열의 주소를 계산한다.

 

st_name + STRTAB

 

const char *name = STRTAB + 0x120 == 0x320

 

* SYMTAB는 자신의 entry에 배열로 접근하기 때문에 ELF32_Sym은 0x10 바이트 단위로 조정되어야 한다.

(인덱스 개념)

 

 

st_name을 컨트롤하고 나면, resolver가 system을 relocate하게 할 수 있고 system('sh')을 호출할 수 있다.

 

4) 마지막으로 전역변수에 구조체를 만들고 esp를 전역변수로 돌려야 한다.

- fake_ebp 사용

 


728x90
반응형

관련글 더보기