pwnable.kr - input

7 minute read

Lets list the files,

input2@pwnable:~$ ls -la
total 44
drwxr-x---   5 root       input2  4096 Oct 23  2016 .
drwxr-xr-x 115 root       root    4096 Dec 22  2020 ..
d---------   2 root       root    4096 Jun 30  2014 .bash_history
-r--r-----   1 input2_pwn root      55 Jun 30  2014 flag
-r-sr-x---   1 input2_pwn input2 13250 Jun 30  2014 input
-rw-r--r--   1 root       root    1754 Jun 30  2014 input.c
dr-xr-xr-x   2 root       root    4096 Aug 20  2014 .irssi
drwxr-xr-x   2 root       root    4096 Oct 23  2016 .pwntools-cache

Lets view the source code for our binary,

input2@pwnable:~$ cat input.c 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>

int main(int argc, char* argv[], char* envp[]){
	printf("Welcome to pwnable.kr\n");
	printf("Let's see if you know how to give input to program\n");
	printf("Just give me correct inputs then you will get the flag :)\n");

	// argv
	if(argc != 100) return 0;
	if(strcmp(argv['A'],"\x00")) return 0;
	if(strcmp(argv['B'],"\x20\x0a\x0d")) return 0;
	printf("Stage 1 clear!\n");	

	// stdio
	char buf[4];
	read(0, buf, 4);
	if(memcmp(buf, "\x00\x0a\x00\xff", 4)) return 0;
	read(2, buf, 4);
        if(memcmp(buf, "\x00\x0a\x02\xff", 4)) return 0;
	printf("Stage 2 clear!\n");
	
	// env
	if(strcmp("\xca\xfe\xba\xbe", getenv("\xde\xad\xbe\xef"))) return 0;
	printf("Stage 3 clear!\n");

	// file
	FILE* fp = fopen("\x0a", "r");
	if(!fp) return 0;
	if( fread(buf, 4, 1, fp)!=1 ) return 0;
	if( memcmp(buf, "\x00\x00\x00\x00", 4) ) return 0;
	fclose(fp);
	printf("Stage 4 clear!\n");	

	// network
	int sd, cd;
	struct sockaddr_in saddr, caddr;
	sd = socket(AF_INET, SOCK_STREAM, 0);
	if(sd == -1){
		printf("socket error, tell admin\n");
		return 0;
	}
	saddr.sin_family = AF_INET;
	saddr.sin_addr.s_addr = INADDR_ANY;
	saddr.sin_port = htons( atoi(argv['C']) );
	if(bind(sd, (struct sockaddr*)&saddr, sizeof(saddr)) < 0){
		printf("bind error, use another port\n");
    		return 1;
	}
	listen(sd, 1);
	int c = sizeof(struct sockaddr_in);
	cd = accept(sd, (struct sockaddr *)&caddr, (socklen_t*)&c);
	if(cd < 0){
		printf("accept error, tell admin\n");
		return 0;
	}
	if( recv(cd, buf, 4, 0) != 4 ) return 0;
	if(memcmp(buf, "\xde\xad\xbe\xef", 4)) return 0;
	printf("Stage 5 clear!\n");

	// here's your flag
	system("/bin/cat flag");	
	return 0;
}

Seems like we have to clear 5 stages to reach the flag

Lets try running it simply,

input2@pwnable:~$ ./input 
Welcome to pwnable.kr
Let's see if you know how to give input to program
Just give me correct inputs then you will get the flag :)
input2@pwnable:~$ ./input  abcdef
Welcome to pwnable.kr
Let's see if you know how to give input to program
Just give me correct inputs then you will get the flag :)

Its printing the default message


Stage 1

The condition to pass stage 1 is ,

    // argv
	if(argc != 100) return 0;
	if(strcmp(argv['A'],"\x00")) return 0;
	if(strcmp(argv['B'],"\x20\x0a\x0d")) return 0;
	printf("Stage 1 clear!\n");	

Lets pass 100 args with the specified values in their respective index given above

#stage1
stage1=['A']*100
stage1[ord("A")]="\x00"
stage1[ord("B")]="\x20\x0a\x0d"
p=process(executable="input",argv=stage1)
p.interactive()

Lets try running this to clear stage 1

aidenpearce369@amun:~/pwnable.kr/INPUT$ python3 exploit.py 

...

Welcome to pwnable.kr
Let's see if you know how to give input to program
Just give me correct inputs then you will get the flag :)
Stage 1 clear!

Stage 2

The condition to pass stage 2 is,

    // stdio
	char buf[4];
	read(0, buf, 4);
	if(memcmp(buf, "\x00\x0a\x00\xff", 4)) return 0;
	read(2, buf, 4);
    	if(memcmp(buf, "\x00\x0a\x02\xff", 4)) return 0;
	printf("Stage 2 clear!\n");

Where 0 and 2 are the file descriptors for stdin and stderror,

Writing the specific values inside the file descriptors

#stage2
fd1,data1=os.pipe()
fd2,data2=os.pipe()
os.write(data1,b"\x00\x0a\x00\xff")
os.write(data2,b"\x00\x0a\x02\xff")
p=process(executable="input",argv=stage1,stdin=fd1,stderr=fd2)

Lets test it,

aidenpearce369@amun:~/pwnable.kr/INPUT$ python3 exploit.py 

...

Welcome to pwnable.kr
Let's see if you know how to give input to program
Just give me correct inputs then you will get the flag :)
Stage 1 clear!
Stage 2 clear!
Exception in thread Thread-1: ...

Stage 3

The condition to pass stage 3 is,

    // env
	if(strcmp("\xca\xfe\xba\xbe", getenv("\xde\xad\xbe\xef"))) return 0;
	printf("Stage 3 clear!\n");

So we need to have an ENV variable named \xde\xad\xbe\xef which has \xca\xfe\xba\xbe as its value

Lets test it,

aidenpearce369@amun:~/pwnable.kr/INPUT$ python2 exploit.py 

...

Welcome to pwnable.kr
Let's see if you know how to give input to program
Just give me correct inputs then you will get the flag :)
Stage 1 clear!
Stage 2 clear!
Stage 3 clear!
Exception in thread Thread-2:
...


Stage 4

To clear the stage 4 we need to pass this condition,

    // file
	FILE* fp = fopen("\x0a", "r");
	if(!fp) return 0;
	if( fread(buf, 4, 1, fp)!=1 ) return 0;
	if( memcmp(buf, "\x00\x00\x00\x00", 4) ) return 0;
	fclose(fp);
	printf("Stage 4 clear!\n");

Here it is opening a file named \x0a and its writing a data of 4 bytes \x00\x00\x00\x00 with file descriptor 1 - stdout

Modifying our exploit,

#stage4
f=open("\x0a","w")
f.write("\x00\x00\x00\x00")
f.close()

Lets test it,

aidenpearce369@amun:~/pwnable.kr/INPUT$ python2 exploit.py 

...

Welcome to pwnable.kr
Let's see if you know how to give input to program
Just give me correct inputs then you will get the flag :)
Stage 1 clear!
Stage 2 clear!
Stage 3 clear!
Stage 4 clear!

Stage 5

To clear stage 5 we need to pass this condition,

    // network
	int sd, cd;
	struct sockaddr_in saddr, caddr;
	sd = socket(AF_INET, SOCK_STREAM, 0);
	if(sd == -1){
		printf("socket error, tell admin\n");
		return 0;
	}
	saddr.sin_family = AF_INET;
	saddr.sin_addr.s_addr = INADDR_ANY;
	saddr.sin_port = htons( atoi(argv['C']) );
	if(bind(sd, (struct sockaddr*)&saddr, sizeof(saddr)) < 0){
		printf("bind error, use another port\n");
    		return 1;
	}
	listen(sd, 1);
	int c = sizeof(struct sockaddr_in);
	cd = accept(sd, (struct sockaddr *)&caddr, (socklen_t*)&c);
	if(cd < 0){
		printf("accept error, tell admin\n");
		return 0;
	}
	if( recv(cd, buf, 4, 0) != 4 ) return 0;
	if(memcmp(buf, "\xde\xad\xbe\xef", 4)) return 0;
	printf("Stage 5 clear!\n");

So the port number will be used from the argument,

saddr.sin_port = htons( atoi(argv['C']) );

So lets add stage1[ord("C")]=5678 in the args data

p=process(executable="input",argv=stage1,stdin=fd1,stderr=fd2,env=env)
#stage 5
msg=remote('localhost',9898)
msg.sendline("\xde\xad\xbe\xef")

We are connecting to socket after the process, because it has to initiate the server on the binary

Lets try running it,

aidenpearce369@amun:~/pwnable.kr/INPUT$ python2 exploit.py 

...

Welcome to pwnable.kr
Let's see if you know how to give input to program
Just give me correct inputs then you will get the flag :)
Stage 1 clear!
Stage 2 clear!
Stage 3 clear!
Stage 4 clear!
Stage 5 clear!

...


Flag

So we have cleared the 5 stages, now we should be able to read the flag

After converting the data into bytes for python3

The final exploit is,

from pwn import *
import os

#stage1
stage1=[b'A']*100
stage1[ord("A")]=b"\x00"
stage1[ord("B")]=b"\x20\x0a\x0d"
stage1[ord("C")]=b"9898" #for stage 5

#stage2
fd1,data1=os.pipe()
fd2,data2=os.pipe()
os.write(data1,b"\x00\x0a\x00\xff")
os.write(data2,b"\x00\x0a\x02\xff")

#stage3
env={b"\xde\xad\xbe\xef":b"\xca\xfe\xba\xbe"}

#stage4
f=open("\x0a","w")
f.write("\x00\x00\x00\x00")
f.close()

#calling process
p=process(executable="input",argv=stage1,stdin=fd1,stderr=fd2,env=env)

#stage 5
msg=remote('localhost',9898)
msg.sendline(b"\xde\xad\xbe\xef")

#gain shell
p.interactive()

And copying this exploit in /tmp/{your own dir} directory and changing the ELF path in the exploit as,

p=process(executable="/home/input2/input",argv=stage1,stdin=fd1,stderr=fd2,env=env)

Adding symlink for that flag, since flag should be in current directory

    // here's your flag
	system("/bin/cat flag");
input2@pwnable:/tmp$ mkdir monish
input2@pwnable:/tmp$ cd monish
input2@pwnable:/tmp/monish$ nano exploit.py

...

input2@pwnable:/tmp/monish$ ln -s /home/input2/flag flag

Lets try running the exploit,

input2@pwnable:/tmp/monish$ python2 exploit.py 
[+] Starting local process '/home/input2/input': pid 349485
[+] Opening connection to localhost on port 9898: Done
[*] Switching to interactive mode
[*] Process '/home/input2/input' stopped with exit code 0 (pid 349485)
Welcome to pwnable.kr
Let's see if you know how to give input to program
Just give me correct inputs then you will get the flag :)
Stage 1 clear!
Stage 2 clear!
Stage 3 clear!
Stage 4 clear!
Stage 5 clear!
Mommy! I learned how to pass various input in Linux :)

Yay!! we got the flag Mommy! I learned how to pass various input in Linux :)