应用侧漏洞与CTF题解:https://wnagzihxa1n.gitbook.io

大土豆安全笔记

整了一波Charles

注册界面一个是用户名,一个是注册码

IMAGE

全局搜索字符串,这若无其事的混淆真是让人不知所措

IMAGE

作个注释

public class RegisterFrame extends JDialog {
    private final JTextField tName; // 用户名
    private final JTextField tSerial; // 序列号
  
    private final JButton bRegister; // 注册按钮
    private final JButton bCancel; // 取消按钮
  
    public RegisterFrame(Frame paramFrame) {
        super(paramFrame, true);
        setTitle("Register Charles");
        this.tName = new JTextField(20);
        this.tSerial = new JTextField(20);
        this.bRegister = new JButton("Register");
        this.bCancel = new JButton("Cancel");
        Container container;
        (container = getContentPane()).setLayout(new MigLayout("wrap,fill", "[label][fill,grow]"));
        container.add(new JLabel("Registered Name:"));
        container.add(this.tName);
        container.add(new JLabel("License Key:"));
        container.add(this.tSerial);
        container.add(this.bCancel, "tag cancel,split 2,span,center");
        container.add(this.bRegister, "tag ok");
        this.bCancel.addActionListener(new ohaK(this));
        // 注册按钮点击事件
        this.bRegister.addActionListener(new ZUnA(this));
        pack();
        if (paramFrame != null) {
            Point point;
            (point = new Point(paramFrame.getLocation())).translate(20, 20);
            setLocation(point);
        } 
        getRootPane().setDefaultButton(this.bRegister);
        getRootPane().getInputMap(1).put(KeyStroke.getKeyStroke("ESCAPE"), "escape");
        getRootPane().getActionMap().put("escape", new RegisterFrame$3(this));
    }
  
    public static void main(String[] paramArrayOfString) { 
    (new RegisterFrame(null)).setVisible(true); 
    }
}

ZUnA调用方法Bvcn.FwRs()判断序列号是否合法,返回null表示注册成功,返回其它表示注册失败

final class ZUnA implements ActionListener {
    ZUnA(RegisterFrame paramRegisterFrame) {}
  
    public final void actionPerformed(ActionEvent paramActionEvent) {
        String str1 = RegisterFrame.FwRs(this.FwRs).getText().trim(); // 获取用户名输入框字符串
        String str2 = RegisterFrame.GSXJ(this.FwRs).getText().trim(); // 获取序列号输入框字符串
        if (str1.length() > 0 && str2.length() > 0) { // 判断两个字符串长度
            String str;
            if ((str = Bvcn.FwRs(str1, str2)) != null) { 
                // 注册失败
                ExtendedJOptionPane.FwRs(this.FwRs, str, "Charles Registration", 2);
                return;
            }
            // 注册成功
            ExtendedJOptionPane.FwRs(this.FwRs, "Thank you for registering. Charles will now close. Please start Charles again to continue.", "Charles Registration", 1);
            CharlesContext charlesContext;
            (charlesContext = CharlesContext.getInstance()).getConfiguration().getRegistrationConfiguration().setName(str1);
            charlesContext.getConfiguration().getRegistrationConfiguration().setKey(str2);
            charlesContext.exit(0, true);
        } 
    }
}

所以我们重点关注方法Bvcn.FwRs(String, String),如果构造Bvcn对象没有出问题,就会返回null,所以校验逻辑肯定在类Bcvn的构造函数里

public static String FwRs(String paramString1, String paramString2) {
    try {
        Bvcn bvcn = new Bvcn(paramString1, paramString2);
    } catch (LicenseException licenseException) {
        return (paramString1 = null).getMessage();
    } 
    GSXJ = paramString1 = paramString1;
    return null;
}

那么爆破的思路就在这里了

再处理一下入口十秒倒计时的问题就可以用了

IMAGE

返回true即可

public static boolean FwRs() {
    Bvcn bvcn;
    return (bvcn = GSXJ).InuZ;
}

这里改为显示在界面上的用户名

public static String InuZ() {
    Bvcn bvcn = GSXJ;
    switch (ohaK.FwRs[bvcn.KRBh.ordinal()]) {
        case 1:
            return bvcn.Gwbn;
        case 2:
            return bvcn.Gwbn + " - Site License";
        case 3:
            return bvcn.Gwbn + " - Multi-Site License";
    } 
    return bvcn.Gwbn;
}

毕竟爆破毕竟还是挫了一些,后面是RC5加解密操作进行逻辑校验,有兴趣的可以研究一下,P和Q的补码表示形式如下

>>> hex(-1209970333 & 0xffffffff)
'0xb7e15163'
>>> hex(-1640531527 & 0xffffffff)
'0x9e3779b9'

我不是老中医,也不是老司机,只是习惯性的优化某些软件的使用体验