Reverse

RSA

使用openssl模块 rsa -pubin -text -modulus -in pub.key得到n值,在 factordb.com上分解大素数得到p,q值,脚本生成private.pem。

# coding=utf-8
import math
import sys
from Crypto.PublicKey import RSA
keypair = RSA.generate(1024)
keypair.p = 2859604688904516379356294403726392834xx
keypair.q = 3040087416046019244943281559752724184xx
keypair.e = 65537
keypair.n = keypair.p
Qn = long((keypair.p - 1) * (keypair.q - 1))
i = 1
while (True):
x = (Qn * i) + 1
if (x % keypair.e == 0):
keypair.d = x / keypair.e
break
i += 1
private = open('private.pem', 'w')
private.write(keypair.exportKey())
private.close()

再使用openssl模块 rsautl -decrypt -in flag.enc -inkey private.pem得到flag。

Youngter-drive

多线程题目,首先有upx加壳,脱壳后发现堆栈不平衡,调整平衡后发现主要有两个线程函数,StartAddress函数和sub_41119F函数

CreateThread(, , (LPTHREAD_START_ROUTINE)StartAddress, , , );
hObject = (HANDLE)sub_41116D();
CreateThread(, , sub_41119F, , , );

StartAddress函数主要是对输入逐位加密,将字符串进行了替换,当字符是大写字母时,替换为off_418000处-38,小写则替换后-96

    if ( dword_418008 > - )
{
sub_41112C(&Source, dword_418008);
--dword_418008;
Sleep(0x64u);
sub_41116D();
}

sub_41119F函数是使StartAddress函数的dword_418008再减一位

  while (  )
{
WaitForSingleObject(hObject, 0xFFFFFFFF);
sub_41116D();
if ( dword_418008 > - )
{
Sleep(0x64u);
sub_41116D();
--dword_418008;
}
ReleaseMutex(hObject);
sub_41116D();
}

这就导致了源程序的间隔加密,奇数位加密,偶数位不变,脚本解密得到flag

off_418000 = "QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm"

off_418004 = "TOiZiZtOrYaToUwPnToBsOaOapsyS"

flag=''

for i in range(len(off_418004)):
if i % == :
flag += off_418004[i]
continue
for j,k in enumerate(off_418000):
if off_418004[i] == k:
if chr(j+).isupper():
flag += chr(j+)
else:
flag += chr(j+) print flag

相册

使用apktool box反编译apk,使用ida加载里面的.so文件搜索字符串,其中几串base64值分别是邮箱用户名密码,邮箱即为flag。

CrackMe

首先依据你的用户名创建一个xor表,然后用这个表和密码经过异或计算,得到一个长度为8的checksum(unsigned char checksum[8]),最后检查checksum是否满足一些条件。满足则通过注册,不满足不通过。checksum进入check2进行验证,最终得到check_num == 43924则成功。

分析check2:

_DWORD *__usercall check2@<eax>(int a1@<ebx>, _BYTE *key, _DWORD *a3)
{
int v3; // ST28_4
int v4; // ecx
int v6; // edx
int v8; // ST20_4
int v9; // eax
int v10; // edi
int v11; // ST1C_4
int v12; // edx
char v13; // di
int v14; // ST18_4
int v15; // eax
int v16; // ST14_4
int v17; // edx
char v18; // al
int v19; // ST10_4
int v20; // ecx
int v23; // ST0C_4
int v24; // eax
_DWORD *result; // eax
int v26; // edx if ( *key == )
{
*a3 |= 4u;
v4 = *a3;
}
else
{
*a3 ^= 3u;
}
v3 = *a3;
if ( key[] == )
{
_EAX = a3;
*a3 |= 0x14u;
v6 = *a3;
}
else
{
*a3 &= 0x61u;
_EAX = (_DWORD *)*a3;
}
__asm { aam }
if ( key[] == )
{
*a3 |= 0x84u;
v9 = *a3;
}
else
{
*a3 &= 0xAu;
}
v8 = *a3;
v10 = ~(a1 >> -);
if ( key[] == )
{
*a3 |= 0x114u;
v12 = *a3;
}
else
{
*a3 >>= ;
}
v11 = *a3;
v13 = v10 - ;
if ( key[] == )
{
*a3 |= 0x380u;
v15 = *a3;
}
else
{
*a3 *= ;
}
v14 = *a3;
if ( *(_DWORD *)(*(_DWORD *)(__readfsdword(0x30u) + ) + ) != )
{
if ( key[] == )
{
*a3 |= 0x2DCu;
v17 = *a3;
}
else
{
*a3 |= 0x21u;
}
v16 = *a3;
}
if ( key[] == )
{
*a3 |= 0xA04u;
v18 = (char)a3;
v20 = *a3;
}
else
{
v18 = (char)a3;
*a3 ^= 0x1ADu;
}
v19 = *a3;
_AL = v18 - v13;
__asm { daa }
if ( key[] == )
{
*a3 |= 0x2310u;
v24 = *a3;
}
else
{
*a3 |= 0x4Au;
}
v23 = *a3;
if ( key[] == )
{
result = a3;
*a3 |= 0x8A10u;
v26 = *a3;
}
else
{
*a3 &= 0x3A3u;
result = (_DWORD *)*a3;
}
return result;
}

发现满足条件的key值只有[100, 98, 97, 112, 112, 115, 101, 99],即"dbappsec"

xor函数是将key和user每位对应异或。在013b1b3e处下断点动态调试扣出和密码异或计算的值

需要主要的是,动态调试和执行得到的异或值是不一样的,需要把类似反调试的代码nop掉,

    if ( *(_DWORD *)(__readfsdword() + ) & 0x70 )
v13 = v11 + v12;
*(&v17 + v6) = byte_13C6050[(unsigned __int8)(v8 + v13)] ^ *(&v15 + v5);
if ( *(_DWORD *)(__readfsdword() + ) & 0xFF )
{
v11 = -;
v12 = ;
}

然后得到box是[0x2a,0xd7,0x92,0xe9,0x53,0xe2,0xc4,xx],写脚本得到flag。

a=[0x2a,0xd7,0x92,0xe9,0x53,0xe2,0xc4,xx]
b=[0x64,0x62,0x61,0x70,0x70,0x73,0x65,0x63] #dbappsec
for i in range():
print hex(a[i]^b[i])

equation

jsfuck代码,发现代码中存在很多l,怀疑l后面是混淆的下标整数,脚本处理,得到多元线性方程组

<script>
function deEquation(str) {
for (let i = 0; i <= 1; i++) {
str = str.replace(/l\[(\D*?)](\+l|-l|==)/g, (m, a, b) => 'l[' + eval(a) + ']' + b);
}
str = str.replace(/==(\D*?)&&/g, (m, a) => '==' + eval(a) + '&&');
return str;
}
s="jsfuck";
ss=deEquation(s);
document.write(ss);
</script>

整理成numpy解方程格式,求出flag数组


from scipy.integrate import odeint
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import root,fsolve
def f3(l):
return np.array([l[40]+l[35]+l[34]-l[0]-l[15]-l[37]+l[7]+l[6]-l[26]+l[20]+l[19]+l[8]-l[17]-l[14]-l[38]+l[1]-l[9]+l[22]+l[41]+l[3]-l[29]-l[36]-l[25]+l[5]+l[32]-l[16]+l[12]-l[24]+l[30]+l[39]+l[10]+l[2]+l[27]+l[28]+l[21]+l[33]-l[18]+l[4]-861,
……,
……,
……]
)
sol3_root = root(f3,[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0])
sol3_fsolve = fsolve(f3,[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0])
print sol3_fsolve

数组转化即为flag。

firmware

固件分析,首先在ubuntu中安装工具firmware-mod-kit

 #安装依赖
sudo apt-get install git build-essential zlib1g-dev liblzma-dev python-magic
#安装firmware-mod-kit
git clone https://github.com/mirror/firmware-mod-kit.git
cd firmware-mod-kit/src
./configure
make

使用binwalk提取出固件内容:

 binwalk -e "firmware.bin"

使用firmware-mod-kit解包固件提取内核和文件系统:

 cd firmware-mod-kit
./unsquashfs_all.sh '/home/vicen/Desktop/_firmware.bin.extracted/120200.squashfs'
cd squashfs-root/tmp/
ls

发现tmp目录下有后门文件backdoor

存在upx3.94加壳,脱壳后载入ida,查看字符串发现远程服务器网址,对网址交叉引用查看代码段发现端口值,将md5值提交flag。

Crypto

达芬奇密码

斐波拉契数列乱序,求出密文对应的正确映射次序即为flag。

a=[0,233,3,2584,1346269,144,5,196418,21,1597,610,377,10946,89,514229,987,8,55,6765,2178309,121393,317811,46368,4181,1,832040,2,28657,75025,34,13,17711]
b=[0,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368,75025,121393,196418,317811,514229,832040,1346269,2178309]
c=[0 for i in range(len(a))]
for i in range(len(a)):
for j in range(len(a)):
if a[i]==b[j]:
c[j]=i
s=""
d=''
for i in range(len(s)):
d+=s[c[i]]
print d

救世捷径

有向图最短路问题,根据各向量的权值,使用Dijkstra算法求出最短路径,然后对照字符串得到flag。

import networkx as nx
def Dijkstra(G, start, end):
RG = G.reverse();
dist = {};
previous = {}
for v in RG.nodes():
dist[v] = float('inf')
previous[v] = 'none'
dist[end] = 0
u = end
while u != start:
u = min(dist, key=dist.get)
distu = dist[u]
del dist[u]
for u, v in RG.edges(u):
if v in dist:
alt = distu + RG[u][v]['weight']
if alt < dist[v]:
dist[v] = alt
previous[v] = u
path = (start,)
last = start
while last != end:
nxt = previous[last]
path += (nxt,)
last = nxt
return path G = nx.DiGraph()
G.add_edge(1,2,weight=100)
G.add_edge(2,3,weight=87)
G.add_edge(2,4,weight=57)
G.add_edge(2,5,weight=50)
G.add_edge(2,6,weight=51)
G.add_edge(3,7,weight=94)
G.add_edge(3,8,weight=78)
G.add_edge(3,9,weight=85)
G.add_edge(4,13,weight=54)
G.add_edge(4,14,weight=47)
G.add_edge(4,15,weight=98)
G.add_edge(5,10,weight=43)
G.add_edge(5,11,weight=32)
G.add_edge(5,12,weight=44)
G.add_edge(6,16,weight=59)
G.add_edge(6,17,weight=92)
G.add_edge(6,18,weight=39)
G.add_edge(6,23,weight=99)
G.add_edge(7,19,weight=99)
G.add_edge(8,20,weight=96)
G.add_edge(9,20,weight=86)
G.add_edge(10,21,weight=60)
G.add_edge(11,21,weight=57)
G.add_edge(12,22,weight=47)
G.add_edge(14,10,weight=55)
G.add_edge(16,17,weight=59)
G.add_edge(18,12,weight=53)
G.add_edge(18,24,weight=93)
G.add_edge(21,22,weight=33)
G.add_edge(19,25,weight=88)
G.add_edge(20,25,weight=96)
G.add_edge(22,25,weight=23)
G.add_edge(25,26,weight=75)
rs = Dijkstra(G, 1, 26)
print(rs)

EasyProgram

 #include<stdio.h>
#include<string.h>
int main()
{
FILE *fp = NULL;
char flag[];
fp = fopen("file.txt", "r");
fscanf(fp, "%s", flag);
int i,j,s[],t[],p,x;
char key[]="whoami";
for (i=;i<;i++)
s[i]=i;
for (i=;i<;i++)
t[i]=key[i%(strlen(key))];
j=;
for (i=;i<;i++){
j=(j+s[i]+t[i])%;
p=s[i];s[i]=s[j];s[j]=p;
}
i=;j=;
for (int m=;m<;m++){
i=(i+)%;
j=(j+s[i])%;
p=s[i];s[i]=s[j];s[j]=p;
x=(s[i] + s[j]%)%;
flag[m]=flag[m]^s[x];
}
printf("%s\n", flag );
return ;
}

浪里淘沙

分析单词出现频率,然后按次数排序,找出其中第4,8,11,15,16位单词拼接为flag。

a="tonightsuccessnoticenoticewewesuccesstonightweexamplecryptoshouldwebackspacetonightbackspace......"
def d(s):
print s,a.count(s)
g=a.replace(s,'')
return g
a=d("tonight")
a=d("success")
a=d("notice")
a=d("example")
a=d("should")
a=d("crypto")
a=d("backspace")
a=d("learn")
a=d("found")
a=d("morning")
a=d("we")
a=d("system")
a=d("sublim")
a=d("the")
a=d("user")
a=d("enter")

SameMod

发现n相同,很明显的RSA共模攻击,随便找个共模攻击脚本得到m=10210897103123119104101110119101116104.....

发现像ascii码拼接在一起,分开为 102,108,97,103......得到flag。

RSA系列

  • 已知p、q、e、c系列:RSA、rsarsa、RSAROLL
  • 已知p、q、dq、dp、c系列:RSA1
  • 已知e、n、dp、c系列:RSA2
  • 共模攻击:RSA3、SameMod
  • 低解密指数攻击:rsa2
  • 低加密指数攻击:Dangerous RSA
  • 相同的e与m,gcd(n1,n2)找存在公约数的两个n值得到p,q:RSA5

套路参考https://err0rzz.github.io/2017/11/14/CTF%E4%B8%ADRSA%E5%A5%97%E8%B7%AF/index.html

writeup参考https://beiyuouo.github.io/2019/05/30/ctf-buuctf/

RSA & what

发现相同的明文使用不同e加密,且n相同,想到是共模攻击,攻击得到一堆base64字符串,解密得到这样一段话:

THIS FLAG IS HIDDEN. CAN YOU FIND IT OUT? DO YOU KNOW BASE64? YoungC THINK YOU ARE NOT THAT FAMILIAR WITH BASE64. Base64 is a group of similar binary-to-text encoding schemes that represent binary data in an ASCII string format by translating it into a radix-64 representation. The term Base64 originates from a specific MIME content transfer encoding. The particular set of 64 characters chosen to represent the 64 place-values for the base varies between implementations. The general strategy is to choose 64 characters that are both members of a subset common to most encodings, and also printable. This combination leaves the data unlikely to be modified in transit through information systems, such as E-mail, that were traditionally not 8-bit clean.[1] For example, MIME's Base64 implementation uses A�CZ, a�Cz, and 0�C9 for the first 62 values. Other variations share this property but differ in the symbols chosen for the last two values; an example is UTF-7.

根据这段话给出的提示怀疑是base64加密,验证发现每个base64串解密后再加密果然与原base串不同,于是解密得到一串数值,即为flag。这里给出流程的完整脚本。

 from libnum import n2s,s2n
import base64
import codecs
from gmpy2 import invert
def egcd(a, b):
if a == 0:
return (b, 0, 1)
else:
g, y, x = egcd(b % a, a)
return (g, x - (b // a) * y, y) def bb(c1,c2):
n =
e1 =
e2 =
s = egcd(e1, e2)
s1 = s[1]
s2 = s[2]
if s1<0:
s1 = - s1
c1 = invert(c1, n)
elif s2<0:
s2 = - s2
c2 = invert(c2, n)
m = pow(c1,s1,n)*pow(c2,s2,n) % n
return hex(m)[2:]
#print (n2s(m)) def get_base64_diff_value(s1, s2):
base64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
res = 0
for i in xrange(len(s1)):
if s1[i] != s2[i]:
return abs(base64chars.index(s1[i]) - base64chars.index(s2[i]))
return res def main():
c1=[,,,,]
c2=[,,,,]
ss=''
for i in range(6):
ss+=bb(c1[i],c2[i])
bases=codecs.decode(ss, 'hex')
m=bases.split("\n")
bin_str = ''
for i in m:
steg_line=i
norm_line = steg_line.decode('base64').encode('base64')
diff = get_base64_diff_value(steg_line, norm_line)
pads_num = steg_line.count('=')
if diff:
bin_str += bin(diff)[2:].zfill(pads_num * 2)
else:
bin_str += '' * pads_num * 2
res_str = '' for i in xrange(0, len(bin_str), 8):
res_str += chr(int(bin_str[i:i + 8], 2))
print 'flag{'+res_str+'}'
if __name__ == '__main__':
main()

BUUCTF-writeup的更多相关文章

  1. BuuCTF Web Writeup

    WarmUp index.php <html lang="en"> <head> <meta charset="UTF-8"> ...

  2. BUUCTF 不一样的flag writeup

    感谢BUUCTF提供的学习平台 https://buuoj.cn 题目:不一样的flag 工具:x64dbg 这是一道内存的迷宫题,迷宫是402000处的字符串 根据经验,这应该(a行*b列)的字符, ...

  3. buuctf 随便注 writeup

    1.0 打开页面 显然这个题的考点是注入,那我们来测一下 2.0 sql注入测试 1 2 输入 1' 后发现没有回显,改为 1' --+ 后,有回显,应该在这存在注入点 试一下 1' and 1=1 ...

  4. buuctf admin writeup

    熟悉的登陆注册页面,结合结合题目admin的提示,想到是通过修改admin用户密码或伪造admin身份的方式来以admin账户.查看源码,看到了一个hint: 下载下来,是靶场的源码首先尝试抓包分析, ...

  5. BUUCTF 刮开有奖 WriteUp

    题目链接 https://buuoj.cn/challenges#%E5%88%AE%E5%BC%80%E6%9C%89%E5%A5%96 题解 用IDA打开,按F5反编译,双击进入DialogFun ...

  6. BUUCTF Crypto_WP(2)

    BUUCTF Crypto WP 几道密码学wp [GXYCTF2019]CheckIn 知识点:Base64,rot47 下载文件后,发现一个txt文件,打开发现一串base64,界面之后出现一串乱 ...

  7. 2016第七季极客大挑战Writeup

    第一次接触CTF,只会做杂项和一点点Web题--因为时间比较仓促,写的比较简略.以后再写下工具使用什么的. 纯新手,啥都不会.处于瑟瑟发抖的状态. 一.MISC 1.签到题 直接填入题目所给的SYC{ ...

  8. ISCC2016 WriteUp

    日期: 2016-05-01~ 注:隔了好久才发布这篇文章,还有两道Pwn的题没放,过一阵子放上.刚开始做这个题,后来恰巧赶上校内CTF比赛,就把重心放在了那个上面. 这是第一次做类似于CTF的题,在 ...

  9. 参加 Tokyo Westerns / MMA CTF 2nd 2016 经验与感悟 TWCTF 2016 WriteUp

    洒家近期参加了 Tokyo Westerns / MMA CTF 2nd 2016(TWCTF) 比赛,不得不说国际赛的玩法比国内赛更有玩头,有的题给洒家一种一看就知道怎么做,但是做出来还需要洒家拍一 ...

  10. 爱春秋之戏说春秋 Writeup

    爱春秋之戏说春秋 Writeup 第一关 图穷匕见 这一关关键是给了一个图片,将图片下载到本地后,打开以及查看属性均无任何发现,尝试把图片转换为.txt格式.在文本的最后发现这样一串有规律的代码: 形 ...

随机推荐

  1. 第一章 Django之学习Django所需知识(3)

    所需编程知识 本书读者需要理解基本的面向过程和面向对象编程:流程控制(if, while 和 for),数据结构(列表,哈希表/字典),变量,类和对象. Web 开发经验,正如你所想的,也是非常有帮助 ...

  2. Mybatis在xml文件中处理大于、小于、不等于号的方法

    在mapper.xml使用大于.小于等符号会和xml语法冲突,解决冲突有两种方式. 方法一: 使用转义字符: 字符名称 字符符号 转义字符 大于号 > > 小于号 < < 与 ...

  3. [Python] For 嵌套循环打印图形 nested loop - 练习题

    [python的for循环嵌套打印如下图形] 图形一: ******* ******* ******* ******* 图形二: * *** ***** ******* 图形三: * *** **** ...

  4. Ubuntu系统---中英文问题小记

    Ubuntu系统---中英文问题小记 Ubuntu系统安装的时候,选择English版本,这样进入tty模式,中文提示不会显示乱码,终端下也是提示英文版的信息. Ubuntu 系统中文显示乱码的问题解 ...

  5. 什么是调整后的R方

    当给模型增加自变量时,复决定系数也随之逐步增大,当自变量足够多时总会得到模型拟合良好,而实际却可能并非如此.于是考虑对R2进行调整,记为Ra2,称调整后复决定系数.R2=SSR/SST=1-SSE/S ...

  6. 《图解HTTP》笔记1

    Web 是建立在 HTTP 协议上通信的. HTTP 通常被译为超文本传输协议,但这种译法并不严谨.严谨的译名应该为“超文本转移协议”. 通过发送请求获取服务器资源的 Web 浏览器等,都可称为客户端 ...

  7. asp.net用sql数据库生成json字符串并显示出来

    use Shop ,) )) insert into DictBase select '包装' UNION ALL select '价格' UNION ALL select '品牌' 工厂方法模式 I ...

  8. 五十六. playbook基础 、 playbook进阶

    1.playbook练习 安装Apache并修改监听端口为8080 修改ServerName配置,执行apachectl -t命令不报错 设置默认主页hello world 启动服务并设开机自启   ...

  9. leetcode解题报告(10):Merge Two Sorted Lists

    描述 Merge two sorted linked lists and return it as a new list. > The new list should be made by sp ...

  10. 带发送FIFO缓冲的RX232串口发送以及把众多文件变成“黑匣子”用于其它工程的调用

    如果需要发送端不断地接收新的数据,而发送端的数据传输率低就需要一个缓冲器FIFO来缓冲数据.当你为别人做项目只是想实现功能而不想让自己的代码让别人看到,想保护自己的算法时,你可以用以下的方法.我使用的 ...