PW 给的一道CTF题,由于实验吧把这一道题目归类于逆向,那么这个就是我国光做出来的第一道”逆向”题目啦。

题目

You see the doors to the loading bay of the hangar, but they are locked. However, you are able to extract the password verification program from the control panel… Can you find the password to gain access to the loading bay?

你可以看到机库的装货门,但是它们被锁上了。但是,您可以从控制面板中提取密码验证程序…你能找到进入装货港的密码吗?

附件

bitwise.py

#!/usr/bin/env python
user_submitted = raw_input("Enter Password: ")

if len(user_submitted) != 10:
  print "Wrong"
  exit()


verify_arr = [193, 35, 9, 33, 1, 9, 3, 33, 9, 225]
user_arr = []
for char in user_submitted:
  # '<<' is left bit shift
  # '>>' is right bit shift
  # '|' is bit-wise or
  # '^' is bit-wise xor
  # '&' is bit-wise and
  user_arr.append( (((ord(char) << 5) | (ord(char) >> 3)) ^ 111) & 255 )

if (user_arr == verify_arr):
  print "Success"
else:
  print "Wrong"

bitwise.java

import java.util.*;

public class Main {
    public static void main(String[] args) {
        System.out.print("Enter Password: ");
        Scanner s = new Scanner(System.in);
        String user_key = s.next();
        if (user_key.length() == 10) {
            System.out.println("Wrong");
            return;
        }

        char[] verify_arr = {193, 35, 9, 33, 1, 9, 3, 33, 9, 225};

        ArrayList<Character> user_arr = new ArrayList<Character>();
        char[] user_submitted_arr = user_key.toCharArray();
        System.out.println(user_submitted_arr.length);

        for (char ch : user_submitted_arr) {
            user_arr.add((char)((((ch << 5) | (ch >> 3)) ^ 111) & 255));
            System.out.println(user_arr);
        }

        int i;
        for(i = 0; i < 10; i++) {
            if (!user_arr.get(i).equals((char)verify_arr[i])) {
                System.out.println("Wrong");
                return;
            }
        }
        System.out.println("Success");
    }
}

思路

由于本人Java水平一般般这里就不去解读Java代码了,所以来直接阅读Python代码。

简单分析代码

这里我在源代码基础上直接加上注释吧,方便阅读

#!/usr/bin/env python
user_submitted = raw_input("Enter Password: ")
# 提示输入密码并记录此刻用户的输入值  用户输入的密码值 存入 user_submitted 变量中

if len(user_submitted) != 10:
  print "Wrong"
  exit()
# 如果用户输入的密码长度不是10位 输出 Wrong 并结束程序

verify_arr = [193, 35, 9, 33, 1, 9, 3, 33, 9, 225]
# 定义一个数组 verify_arr 用来验证作用
user_arr = []
# 定义并初始化一个 user_arr 数组变量

for char in user_submitted:
# 循环提取user_submitted变量中的字符
  # '<<' is left bit shift
  # '>>' is right bit shift
  # '|' is bit-wise or
  # '^' is bit-wise xor
  # '&' is bit-wise and
  user_arr.append( (((ord(char) << 5) | (ord(char) >> 3)) ^ 111) & 255 )
# 对这个字符进行 加密处理 这里是核心加密代码,加密后的代码放入user_arr这个变量里面
if (user_arr == verify_arr):
# 拿user_arr与验证数组verify_arr 来做判断 输入正确或者错误
  print "Success"
else:
  print "Wrong"

突破

这一题目的代码很容易理解,从代码中可以看出这一题想让我们写出正确的密码,flag 就是密码值。 一次性还原出10位数密码有点难度,这里我的思路是11位的去还原。

POC代码第一版

第一版代码比较繁琐,手工输入字典,然后手工一位一位的来破解,效率不是很高,虽然最后也可以解出密码来。

#!/usr/bin/env python
# -*- coding:utf-8 -*-
zidian =['{','}','[',']','\'','|',';',':','"',',','<','>','.','/','?','0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','!','!','@','#','$','^','&','*','(',')','-','+']
jiami = (int)(input("请输入被加密后的密文:"))
for i in range(0,(len(zidian)-1)):
  g = ( (((ord(zidian[i]) << 5) | (ord(zidian[i]) >> 3)) ^ 111) & 255 )
  if (g == jiami):
      print("密码原文是")
      print (zidian[i])

效果演示

POC 代码第二版

我们每次破解还原1位密码还得重新来运行这个脚本,现在思考能不能一直循环的来运行呢?

#!/usr/bin/env python
# -*- coding:utf-8 -*-
zidian =['{','}','[',']','\'','|',';',':','"',',','<','>','.','/','?','0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','!','!','@','#','$','^','&','*','(',')','-','+']
while(1):
    jiami = (int)(input("请输入被加密后的密文:"))
    for i in range(0,(len(zidian)-1)):
        g = ( (((ord(zidian[i]) << 5) | (ord(zidian[i]) >> 3)) ^ 111) & 255 )
        if (g == jiami):
            print("密码原文是")
            print(zidian[i])
            panduan = raw_input("是否继续输入?[Y/N]")
            if(panduan == 'N' or panduan =='n'):
                print("Bye Bye~")
                exit()

效果演示

可以看到效率提高了很多,尤其是在密码位数比较多的情况下就会显示出差距了。

POC 代码第三版

这个脚本用起来还不够方便,因为是一位一位去破解的,而且最后为了拿到密码值,我们还得一位一位的拼接起来,现在思考能不能最后把密码值完全拼接好再print出来呢?

#!/usr/bin/env python
# -*- coding:utf-8 -*-
zidian =['{','}','[',']','\'','|',';',':','"',',','<','>','.','/','?','0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','!','!','@','#','$','^','&','*','(',')','-','+']
jieguo = []
while(1):
    jiami = (int)(input("请输入被加密后的密文:"))
    for i in range(0,(len(zidian)-1)):
        g = ( (((ord(zidian[i]) << 5) | (ord(zidian[i]) >> 3)) ^ 111) & 255 )
        if (g == jiami):
            print("密码原文是")
            print(zidian[i])
            jieguo.append(zidian[i])
            panduan = raw_input("是否继续输入?[Y/N]")
            if(panduan == 'N' or panduan =='n'):
                print("Bye Bye~")
                print("最后的密码是:")
                print(jieguo)
                exit()  

效果演示

关于第 N 个版本

当然目前来看这个POC验证代码在用户体验上还不是那么友好而且代码中zidian这个在代码中显得过于臃肿。后期肯定还是可以再完善这个代码的。后期的改进方向:

  • 从文件中加载字典
  • 1次性输入全部密码 然后解密
  • 图形化界面
  • WEB界面
  • 添加修改算法规则,灵活破解‘

当然真正要全部实现这些功能的话,在Python代码上面还得多多的下功夫才可以。↖(^ω^)↗加油

点评

当初 Python 还没有系统的学习,属实有点菜,但是还是有成功的喜悦的,迷茫且充实着。

本文可能实际上也没有啥技术含量,但是写起来还是比较浪费时间的,在这个喧嚣浮躁的时代,个人博客越来越没有人看了,写博客感觉一直是用爱发电的状态。如果你恰巧财力雄厚,感觉本文对你有所帮助的话,可以考虑打赏一下本文,用以维持高昂的服务器运营费用(域名费用、服务器费用、CDN费用等)

微信
支付宝

没想到文章加入打赏列表没几天 就有热心网友打赏了 于是国光我用 Bootstrap 重写了一个页面 用以感谢 支持我的朋友,详情请看 打赏列表 | 国光