[CTF从0到1学习] 二CTF WEB安全

Posted 南岸青栀*

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CTF从0到1学习] 二CTF WEB安全相关的知识,希望对你有一定的参考价值。

[CTF从0到1学习] 二、CTF WEB安全

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");
?>

flagHow_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!’);GZ(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!’);elseeval(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))) 以上是关于[CTF从0到1学习] 二CTF WEB安全的主要内容,如果未能解决你的问题,请参考以下文章

[CTF从0到1学习] 二CTF WEB安全

[CTF从0到1学习] 二CTF 密码学

[CTF从0到1学习] 二CTF 密码学

[CTF从0到1学习] 二CTF 密码学

[CTF从0到1学习] 二CTF 密码学

[CTF从0到1学习] BUUCTF WEB部分 wp(待完善)