I was making a simple CTF(Capture The Flag) problem with docker. The current case is simple(It's not a real problem, it's just a test.); enter a specified string and get a shell(/bin/bash
) if correct.
The original C source code is here. If the user's input is exactly 1n1tTheJourney2Pwnable
, the program runs get_shell()
which gives /bin/sh
to the user.
// welcome.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
void alarm_handler() {
puts("TIME OUT");
exit(-1);
}
void initialize() {
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
signal(SIGALRM, alarm_handler);
alarm(30);
}
void get_shell() {
char *cmd = "/bin/sh";
char *args[] = {cmd, NULL};
execve(cmd, args, NULL);
}
int main() {
char buf[32];
initialize();
printf("input: ");
scanf("%s", buf);
if(strcmp(buf,"1n1tTheJourney2Pwnable") == 0) {
printf("SUCCESS!!\n");
get_shell();
} else {
printf("Wrong..!!\n");
}
return 0;
}
Here is the Dockerfile
for the problem.
FROM ubuntu:20.04
# user name and the title of the problem are identical
ENV user welcome
ENV port 2023
RUN apt-get update
RUN apt-get install -y
RUN apt-get install -y socat gcc
RUN adduser $user
WORKDIR /home/$user
ADD ./$user.c /home/$user/$user.c
ADD ./flag /home/$user/flag
RUN gcc -o /home/$user/$user /home/$user/$user.c
RUN chown $user:$user /home/$user/$user
RUN chown $user:$user /home/$user/flag
RUN chmod 755 /home/$user/$user
RUN chmod 750 /home/$user/flag
USER $user
EXPOSE $port
CMD socat -T 30 TCP-LISTEN:$port,reuseaddr,fork EXEC:/home/$user/$user
I build that Dockerfile
as below:
sudo docker build -t system_welcome <dockerfile location>
sudo docker run -p 2023:2023 system_welcome
Of course, this problem is very easy as just typing the following string after establishing a connection by hitting the command nc 127.0.0.1 2023
. However, I wanted to demonstrate the basic usage of pwntool
. So I wrote a simple script doing so.
from pwn import context, remote, process
context.log_level = 'debug'
#p = process('./welcome')
p = remote('127.0.0.1', 2023)
p.recvuntil(b'input: ')
p.sendline(b'1n1tTheJourney2Pwnable')
p.interactive()
So, the program does work as expected and obtains the shell(/bin/sh
). However, as suggested in the picture below, the shell doesn't print anything as a result of cat
commands, even though the interactive program received the data. Oddly, results from other commands like id
or ls
are being shown correctly.
It's highly expected of pwntool
's problem or Dockerfile
's problem, but I couldn't find any solution or tips to resolve this problem, so I need some help related to this.
The root cause of the problem was the difference between \r\n
and \n
. In the content of the previous question, pwntool
received the string data with a delimiter of \r\n
, which is used as a new line character in Windows OS. However, I was using Linux(Ubuntu 22.04@WSL2 on Windows 11).
After inspection, I found flag
wasn't written on Linux whose delimiter is \n
. (Assumably it would be created in Windows or Mac OS.)
So, I deleted my flag
file with \r\n
delimiter and created the flag
file again in Linux entirely. After revision, everything worked as I intended and expected.
The main cause of the problem was near but I couldn't see for nearly 18 hours(Yeah, it may sound hilarious.). I hope my case would be helpful who having troubles with similar problems with mine. To conclude, neither Docker nor the "pwn" posed any issues.
More to read: What is the difference between \r\n, \r, and \n?