CTF逆向--.NET与Python篇
题目(来源:Jarvis-OJ):
- Classical Crackme
- Classical CrackMe2
- FindKey
- Login
Classical Crackme
首先查壳
没有壳,不过发现这是一个.net的程序,将其拖进dnSpy中,找到主程序,同时发现关键代码,如下所示:
private void u202Cu200Bu206Au202Au206Du206Bu202Du206Fu202Du200Cu200Eu206Bu202Eu202Eu202Cu202Bu206Au206Du206Eu202Bu206Eu200Fu202Du200Eu202Cu200Fu200Du200Fu202Bu200Cu202Au206Du206Au206Eu202Du200Du200Cu206Bu202Au202Du202E(object obj, EventArgs eventArgs)
{
string s = this.u200Eu206Fu206Au200Fu206Eu202Cu206Cu200Cu206Au200Bu206Eu202Du206Bu202Du200Fu206Bu202Bu200Cu206Bu202Du206Du202Bu206Bu200Cu206Fu206Du206Au202Du200Fu202Eu200Bu206Du202Cu200Du200Du202Cu200Fu202Eu202Eu206Au202E.Text.ToString();
byte[] bytes = Encoding.Default.GetBytes(s);
string a = Convert.ToBase64String(bytes);
string b = "UENURntFYTV5X0RvX05ldF9DcjRjazNyfQ==";
if (a == b)
{
MessageBox.Show("注册成功!", "提示", MessageBoxButtons.OK);
}
else
{
MessageBox.Show("注册失败!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Hand);
}
}
可以看到,如果输入的字符串进行base64编码后若和字符串‘UENURntFYTV5X0RvX05ldF9DcjRjazNyfQ==’一致,则显示注册成功,将该字符串进行base64解码,得到flag
Flag:PCTF{Ea5y_Do_Net_Cr4ck3r}
Classical CrackMe2
首先查壳
.net程序,先拖进ILSpy(dnSpy的编码看起来太辛苦了-_-|||,等一下需要动态调试的时候再用它)找到主函数中的关键代码,如下所示
可以看到对用户输入的flag限制条件为:
(1)不为空
(2)进行AES加密后再经过base64编码必须等于某个字符串
既然这样我们就通过动态调试来找出key和加密后字符串,将文件拖进dnSpy,找到上面的函数,给获取key的地方下个断点,如下所示
开始调试,运行到该位置时得到key
右键->show in memory window->memory 1,key如下
然后找加密后的字符串,接下来在关键判断的位置下断点
调试,得到加密后的字符串”x/nzolo0TTIyrEISd4AP1spCzlhSWJXeNbY81SjPgmk=”
下面就可以写脚本获取flag
import base64,binascii from Crypto.Cipher import AES key = 'pctf2016pctf2016pctf2016pctf2016' result = 'x/nzolo0TTIyrEISd4AP1spCzlhSWJXeNbY81SjPgmk=' after_encrypt = binascii.b2a_hex(base64.b64decode(result)) a = AES.new(key) flag = a.decrypt(after_encrypt.decode('hex')) print flag
Flag:PCTF{Dot_Net_UnPack3r_yoo}
FindKey
这是一道pyc逆向,直接百度pyc在线逆向,找到相应的网站后上传需要逆向的pyc文件,接下来就能得到源码,如下所示
#!/usr/bin/env python # encoding: utf-8 # 访问 http://tool.lu/pyc/ 查看更多信息 import sys lookup = [196,153,149,206,17,221,10,217,167,18,36,135,103,61,111,31,92,152,21,228,105,191,173,41,2,245,23,144, 1,246,89,178,182,119,38,85,48,226,165,241,166,214,71,90,151,3,109,169,150,224,69,156,158,57,181,29, 200,37,51,252,227,93,65,82,66,80,170,77,49,177,81,94,202,107,25,73,148,98,129,231,212,14,84,121,174, 171,64,180,233,74,140,242,75,104,253,44,39,87,86,27,68,22,55,76,35,248,96,5,56,20,161,213,238,220,72, 100,247,8,63,249,145,243,155,222,122,32,43,186,0,102,216,126,15,42,115,138,240,147,229,204,117,223,141, 159,131,232,124,254,60,116,46,113,79,16,128,6,251,40,205,137,199,83,54,188,19,184,201,110,255,26,91,211, 132,160,168,154,185,183,244,78,33,123,28,59,12,210,218,47,163,215,209,108,235,237,118,101,24,234,106,143, 88,9,136,95,30,193,176,225,198,197,194,239,134,162,192,11,70,58,187,50,67,236,230,13,99,190,208,207,7,53, 219,203,62,114,127,125,164,179,175,112,172,250,133,130,52,189,97,146,34,157,120,195,45,4,142,139] pwda = [188,155,11,58,251,208,204,202,150,120,206,237,114,92,126,6,42] pwdb = [53,222,230,35,67,248,226,216,17,209,32,2,181,200,171,60,108] flag = raw_input('Input your Key:').strip() if len(flag) != 17: print 'Wrong Key!!' sys.exit(1) flag = flag[::-1] for i in range(0, len(flag)): if ord(flag[i]) + pwda[i] & 255 != lookup[i + pwdb[i]]: print 'Wrong Key!!' sys.exit(1) print 'Congratulations!!'
很简单,将其的代码复制下来就可得到flag,脚本如下所示
lookup = [196,153,149,206,17,221,10,217,167,18,36,135,103,61,111,31,92,152,21,228,105,191,173,41,2,245,23,144, 1,246,89,178,182,119,38,85,48,226,165,241,166,214,71,90,151,3,109,169,150,224,69,156,158,57,181,29, 200,37,51,252,227,93,65,82,66,80,170,77,49,177,81,94,202,107,25,73,148,98,129,231,212,14,84,121,174, 171,64,180,233,74,140,242,75,104,253,44,39,87,86,27,68,22,55,76,35,248,96,5,56,20,161,213,238,220,72, 100,247,8,63,249,145,243,155,222,122,32,43,186,0,102,216,126,15,42,115,138,240,147,229,204,117,223,141, 159,131,232,124,254,60,116,46,113,79,16,128,6,251,40,205,137,199,83,54,188,19,184,201,110,255,26,91,211, 132,160,168,154,185,183,244,78,33,123,28,59,12,210,218,47,163,215,209,108,235,237,118,101,24,234,106,143, 88,9,136,95,30,193,176,225,198,197,194,239,134,162,192,11,70,58,187,50,67,236,230,13,99,190,208,207,7,53, 219,203,62,114,127,125,164,179,175,112,172,250,133,130,52,189,97,146,34,157,120,195,45,4,142,139] pwda = [188,155,11,58,251,208,204,202,150,120,206,237,114,92,126,6,42] pwdb = [53,222,230,35,67,248,226,216,17,209,32,2,181,200,171,60,108]flag = "" for i in range(17): flag += chr(lookup[i+pwdb[i]] - pwda[i]&255) print flag[::-1]
Flag:PCTF{PyC_Cr4ck3r}
Login
首先查壳
没壳,拖进IDA,F12查看字符串,发现里面出现了python的标志
按理来说一般的c程序是不会出现python的,但是这里却出现了大量的Py前缀,这说明什么呢,说明这个exe实际上是一个python转exe的程序(你问我为什么会知道?因为我之前在HXBCTF征题的时候就出了道Python转exe的题打算坑一坑人/ ͝ ὡ ͝ /),在网上下一个pyinstxtractor.py就可将其解压,然后查看解压后的文件夹
首先看到有一堆API的dll,不管它,然后还看到一个Python35.dll,查一下壳,发现是UPX加壳的,使用脱壳机脱掉后,丢进IDA里查看,点击F12查看字符串,一大堆字符串-_-||,尝试搜索一下flag,然后发现了这个
查看引用后来到了这个函数
就这样来到了核心代码的位置,这里可以看到if ( v3 != (v4 ^ byte_1E253040[v3]) )这个if判断是关键判断,只有当其正确,整个while循环才会执行到输出Congratulation处而V4就是用户输入的Password,因此就可以写一个脚本来得出flag
a = [0x50 ,0x78 ,0x76 ,0x6B ,0x34 ,0x6B ,0x59 ,0x63 ,0x49 ,0x56 ,0x6C ,0x4A ,0x53 ,0x65 ,0x4F ,0x3F] count = 0 flag = '' for i in range(len(a)): for i in range(33,127): if i^a[count] == count: flag += chr(i) count += 1 break print flag
这里的a就是上面代码中的byte_1E253040数组
Flag:Pyth0n_dA_fA_hA0
- 移位寄存器的工作原理
- ROM 单元
- 超前进位加法器
- 算法和数据结构—— 查找和排序
- CVE 2017-0199漏洞利用的新姿势
- Java 正则表达式 StackOverflowError 问题及其优化
- 权限后门系列之一:手动打造WordPress权限后门
- 浅谈用户行为分析之用户身份识别:cookie 知多少?
- 串口通信控制器的Verilog HDL实现(四) 接收模块的Verilog HDL 实现
- 串口通信控制器的Verilog HDL实现(三) 发送模块的Verilog HDL 实现
- 串口通信控制器的Verilog HDL实现(二) 波特率发生器模块
- 串口通信控制器的Verilog HDL实现(一) 顶层模块
- 双口同步RAM
- 单口RAM
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法