For this challenge we are given a source file main.c,
so the first thing we should generally do is to read the source code.
main.c snippet
int main() {
char *buf = malloc(32);
memset(buf, 0, 32);
puts("Type a string that has 'lit' in it and does not have 'lit' in it at the same time");
buf[read(0, buf, 32) - 1] = 0;
int contains = 0;
int notContains = strstr(buf, "lit") == NULL;
for (int i = 0; i < 32 - 2; i++) {
if (!strncmp(buf + i, "lit", 3)) contains = 1;
}
free(buf);
if (contains && notContains) {
win();
}
else {
puts("Failed");
}
exit(0);
}This code reads 32 characters from stdin and sets the last character to a null byte.
buf[read(0, buf, 32) - 1] = 0;Then we define contains and notContains and we want both to be 1 (true) to call win(). We have
int notContains = strstr(buf, "lit") == NULL;Looking at the manpage for strstr, we see that buf is expected to be a null terminated string
and returns NULL when the string is not found. Notice that the read function used to read into buf
has no problem reading null bytes... hmm...
To check for contains, we go through every character buf[i] of the buffer (except the last 2) and
check if the 3 character substring starting at i matches "lit".
Notice that we always traverse the whole buffer regardless of any null bytes.
Do we see the solution now?
Consider the input litctf. After reading, buf will contain
0 1 2 3 4 5 6 7 8 9 ...
--------------------------------------------------------
l i t c t \x00 \x00 \x00 \x00 \x00 ...
(there is no f because it gets replaced by a null byte)
strstr will search indices 0 to 4 while the contains loop goes through 0 to 29. If we put "lit" after index 4,
we solve the challenge.
This can be done by simply putting a null byte in the input. An example string that gives us the flag is
A\x00litA
where A can be any character. buf for this string will look like below:
0 1 2 3 4 5 6 7 8 9 ...
--------------------------------------------------------
A \x00 l i t \x00 \x00 \x00 \x00 \x00 ...
strstr will search the substring "A" and not find "lit", while the loop will find "lit" at index 2.
Note that we can type a null byte in most terminal emulators by pressing ctrl+@ or ctrl+shift+2.
We can also printf a null byte into a file and pipe it into netcat:
printf 'A\x00litA' >tmp && cat tmp - | nc litctf.org 31770