final 40% 1.reverse 4 2.code auditing 4 3.pwn 4

hurdle:

顺序一:

顺序二:

什么是reversing? -阅读反汇编 -恢复C伪代码 -识别常见代码结构(条件、循环、switch) -判断变量类型 -找出bug(可能是一题)

patterns

compare-> conditional jump -> if compare + jump + backward jump -> while 连续的 mov -> 初始化数组 结构体字段通过固定偏移访问

结构正确 变量名有意义 逻辑清晰

评分标准: var_20 r8 v13

int i char *buffer struct node *next size_t size counter += 1

patterns

1.大多数计算都是在寄存器中发生的 mov eax, [rbp-0x4] add eax, 1 mov [rbp-0x4], eax i++

2.常用寄存器 RAX return value RDI RSI RDX RCX RSP stack pointer RBP frame pointer

mov dword ptr [rbp-0x14], edi int x = arg1

stack frame: push rbp mov rbp, RSP sub rsp,

rbp-0x4, rbp-0x8 –> local variables rbp+0x8,rbp+0x10 –> caller’s frame

mov mov al, [x] char mov ax, [x] short eax, 4 bytes int rax, 8 bytes long pointer

mov al, [rbp-0x1] char flag int flag (x)

pointer dereference: mov rax, qword ptr [rbp-0x18] mov eax, dword ptr [rax+4]

struct something { int field0; int field1; }

struct something *obj; int x = obj->field1;

control flow:

if/ if-else

cmp eax, 5 jl .L1 … .L1:

if (x >= 5){ … }

cmp eax, ebx jne fail

if (a != b) goto fail

je jne jg jl jge jle

while

.Lloop: cmp eax, 0 je .Lend … loop body … jmp .Lloop .Lend:

while (x != 0){ … }

for

mov local_i, 0

i++ backward jump

mov dword ptr [rbp-4], 0 .Lcond: cmp dword ptr [rbp-4], edi jge .Lend … body … add dword ptr [rbp-4], 1 jmp .Lcond .Lend:

for (int i=0; i < arg1; i++){ … }

switch-case:

Case A:连续小整数 (jump table) cmp eax, 5 ja default jmp qword ptr [rax*8 + table]

switch(x){ case 0: … case 1: … case 2: … }

Case B:稀疏整数 (多个 cmp + jmp) cmp eax, 4 je L4 cmp eax, 100 je L100 …

char short int long pointer

mov al, [rbp-0x1] mov eax, [rbp-0x4] mov rax, [rbp-0x18]

1.mov指令宽度决定变量类型 al char ax short eax int rax long/pointer

mov rax, qword ptr [rbp-0x18] void *ptr

2.指针dereference的识别

mov rax, qword ptr [rbp-0x18] ;ptr mov eax, dword ptr [rax+4] ;ptr->field1

3.结构体的汇编证据 3.1 固定大小的对分配 mov edi, 32 call malloc

3.2 多个字段通过固定偏移访问 mov rax, qword ptr [rdi] ;field0 mov eax, dword ptr [rdi+0x8] ;field1 mov byte ptr [rdi+0xC], 1 ;field2

struct X { long field0; int field1; char flag }

4.数组识别 mov eax, [rbp-0x20 + rdx*4]

数组访问 pattern = base + index * element_size

rdx elsement_size [rbp-0x20]

movsx eax, byte ptr [rbp-0x20 + rdx] char arr[]

mov eax, dword ptr [rbp-0x20 + rdx*4] int arr[]

5.动态数组 vs 静态数组 静态数组: sub rsp, 0x40 mov [rbp-0x40 + rdx*4]

动态数组:malloc | calloc mov edi, rax ;size call malloc

gdb b func run stepi , ni info registers x/20gx addr continue

IDA

int counter int index struct node *next char flag int len

技巧: 1.识别函数的基本结构 2.识别控制流 3.识别关键变量

add dword ptr [rbp-4], 1 i++

4.推测语义

5.组合成伪代码 if(…){

}else{

}

for(…){

}

struct node { int val; struct node *next;

}

bug finding: out-of-bounds integer overflow pointer dereference -> null return


code auditing

明显的漏洞 (buffer overflow, 格式化字符串…) subtle vulnerabilities (整数溢出, 类型转换错误…) 逻辑漏洞(missing checks, 错误的return) API misuse (不检查返回值, 用错大小…)

常见漏洞类型 一.BAD API Usage gets()

char s[4] gets(s)

2.strcpy()

char s[4] strcpy(s, argv[1])

3.strncpy()

strncpy(buf, input, 16); printf("%s\n", buf)

null-byte

4.printf(argv[1]) - fmt printf(argv[1])

%s %n %x

任何用户输入直接传给printf,不带格式化字符串,就是 format string attack

5.memset/memcpy/memmove 参数反了

memset(void *s, int c, size_t n);

memset(p, 100, 0) memset(dest, size, ‘A’)

memset 2

二. Integer Overflow / Underflow

int len = header + size; if (len > buffer_size) return; read(fd, buf, len);

len 负数(signed int overflow)

signed -> unsigned int len = INT_MAX len += 10; //overflow, len becomes negative read(fd, buf, len); //3 size_t (unsigned)

0xfffffffffffffffc

越界 覆盖整个堆/栈 RCE

任何 signed int 序列最后传给 size_t 的 API, 都是有风险。

read write malloc memcpy calloc(double-multiply overflow)

类型截断问题

整数被转换成short

int become_user (int uid); short assume_priv(shor uid);

uid=0x10000000 传给short -> 截断: 0x0000

short 0 -> root -> 提权

Array Out-of-Bounds 越界访问

固定长度数组写越界 for循环上界错误 通过整数溢出绕过边界检查

char buf[16] for (int i=0; i<=16; i++){ buf[i] = input[i]; }

HEAP BUGS (UAF, Double Free) use-after-free double free

free(ptr); free(ptr); //double free

Logic Bugs (逻辑漏洞)

1.忘记检查malloc

2.忘记 return/ break/ early exit

if(x<0>) free(buf); //forgot return buf[0] = ‘A’

3.Error path 返回了错误的状态 if(len < 0) return 1; if(len > max) return 1;

process(buf, len); return 0;

4.检查顺序不对: TOCTOU

if(!exists(“file”)){ do_stuff(); } -> 修改文件 race condition open(“file”)

Race Condition (竞态条件) 1.检查某个资源 2.进行一些操作 3.再次使用相同资源

if(!access(filename)){ //ToC do_something(); //ToU f=open(filename); }

check 和使用 use 之间有时间差,可以被攻击者利用

Code Auditing 实战策略 1.大框架:Top-down vs Bottom-up Top-down(从main开始) Bottom-up(从输入开始)

高危函数 上下界 i <= size i < length index

类型转换 signed unsigned long int int short

hidden bug