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
Offset은 symbol에 대한 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
STRTAB은 symbols 이름에 대한 문자열을 저장하는 table이다.
3) SYMTAB
Symbol 정보를 가지고 있는 테이블.
각 entry는 Elf32_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 사용
Stack Frame & 함수 호출 규약 (32bit, 64bit) (0) | 2020.05.30 |
---|---|
[Back to Basic] Linux exploitation & Mitigation #1 (0) | 2020.04.06 |
[Heap Exploitation] Poison null byte(Shrink chunk) (0) | 2020.01.30 |
[Heap Exploitation] Overlapping Chunks 2 (0) | 2020.01.26 |
[Heap Exploitation] Overlapping chunks (0) | 2020.01.17 |