姚小宝 发表于 2019-6-24 18:38

2019SCTF 部分WP

本帖最后由 yechen123 于 2019-6-25 21:24 编辑

题目可在xctf社区获取

strange apk
一道安卓题,直接APKIDE打开。

通过阅读代码发现

public class c
extends Application
{
private String apkFileName;
private String libPath;
protected AssetManager mAssetManager;
protected Resources mResources;
protected Resources.Theme mTheme;
private String odexPath;

private void _(byte[] paramArrayOfByte)
    throws IOException
{
    paramArrayOfByte = _0_(paramArrayOfByte);
    Object localObject = new File(this.apkFileName);
    try
    {
      localObject = new FileOutputStream((File)localObject);
      ((FileOutputStream)localObject).write(paramArrayOfByte);
      ((FileOutputStream)localObject).close();
      return;
    }
    catch (IOException paramArrayOfByte)
    {
      throw new RuntimeException(paramArrayOfByte);
    }
}

private byte[] _0_(byte[] paramArrayOfByte)
{
    int i = 0;
    while (i < paramArrayOfByte.length)
    {
      paramArrayOfByte = ((byte)("syclover".charAt(i % "syclover".length()) ^ paramArrayOfByte));
      i += 1;
    }
    return paramArrayOfByte;
}

public byte[] __(String paramString)
    throws IOException
{
    paramString = getResources().getAssets().open(paramString);
    byte[] arrayOfByte = new byte;
    paramString.read(arrayOfByte);
    return arrayOfByte;
}

protected void attachBaseContext(Context paramContext)
{
    super.attachBaseContext(paramContext);
    try
    {
      paramContext = getDir("sctf_odex", 0);
      localObject = getDir("sctf_lib", 0);
      this.odexPath = paramContext.getAbsolutePath();
      this.libPath = ((File)localObject).getAbsolutePath();
      localObject = new StringBuilder();
      ((StringBuilder)localObject).append(paramContext.getAbsolutePath());
      ((StringBuilder)localObject).append("/sctf.apk");
      this.apkFileName = ((StringBuilder)localObject).toString();
      paramContext = new File(this.apkFileName);
      localObject = new StringBuilder();
      ((StringBuilder)localObject).append("apk size:");
      ((StringBuilder)localObject).append(paramContext.length());
      Log.i("demo", ((StringBuilder)localObject).toString());
      if (!paramContext.exists())
      {
      paramContext.createNewFile();
      _(__("data"));
      }
      paramContext = s.invokeStaticMethod("android.app.ActivityThread", "currentActivityThread", new Class, new Object);
      localObject = getPackageName();
      if (Build.VERSION.SDK_INT < 19) {
      paramContext = (WeakReference)((HashMap)s.getFieldOjbect("android.app.ActivityThread", paramContext, "mPackages")).get(localObject);
      } else {
      paramContext = (WeakReference)((ArrayMap)s.getFieldOjbect("android.app.ActivityThread", paramContext, "mPackages")).get(localObject);
      }
      localObject = new DexClassLoader(this.apkFileName, this.odexPath, this.libPath, (ClassLoader)s.getFieldOjbect("android.app.LoadedApk", paramContext.get(), "mClassLoader"));
      s.setFieldOjbect("android.app.LoadedApk", "mClassLoader", paramContext.get(), localObject);
      paramContext = new StringBuilder();
      paramContext.append("classloader:");
      paramContext.append(localObject);
      Log.i("demo", paramContext.toString());
      return;
    }
    catch (Exception paramContext)
    {
      Object localObject = new StringBuilder();
      ((StringBuilder)localObject).append("error:");
      ((StringBuilder)localObject).append(Log.getStackTraceString(paramContext));
      Log.i("demo", ((StringBuilder)localObject).toString());
      paramContext.printStackTrace();
    }
}

该APK中隐藏着一个data文件,直接修改后缀为zip打开,data解密之后就是一个APK。
上脚本解密
i = "syclover"

f = open("data", "rb")
q = open("datas","wb")

couts = 0
c = f.read(1)
qq = 0
while (1):
    uq = ord(c)^ord(i)
    if (uq<=15):
      q.write(("0x0"+hex(uq)))
    else:
      q.write((hex(uq)))
    couts += 1
    qq += 1
    if (couts%2==0 and couts%16!=0):
      q.write(' ')

    if (couts%16==0):
      q.write('\n')
    c = f.read(1)
    if c==None:
      break
   
q.close()
f.close()

可以把datas里边的数据用winhex以二进制方式存入一个新文件,原来手动存的时候一直显示未预料到文件尾,还以为要手动修复zip,原来是自己的问题,可能是文件尾部多了一些数据,导致CRC校验出错。

最终得到一个新APK。
阅读代码。
protected void onCreate(Bundle paramBundle)
{
    super.onCreate(paramBundle);
    setContentView(2131296285);
    paramBundle = (Button)findViewById(2131165218);
    findViewById(2131165322);
    paramBundle.setOnClickListener(new View.OnClickListener()
    {
      public void onClick(View paramAnonymousView)
      {
      paramAnonymousView = "";
      Object localObject1 = "";
      int i = 0;
      String str = this.val$ed.getText().toString();
      if (str.length() == 30)
      {
          while (i < 12)
          {
            localObject2 = new StringBuilder();
            ((StringBuilder)localObject2).append(paramAnonymousView);
            ((StringBuilder)localObject2).append(str.charAt(i));
            paramAnonymousView = ((StringBuilder)localObject2).toString();
            i += 1;
          }
          Object localObject2 = f.sctf(paramAnonymousView);
          paramAnonymousView = (View)localObject1;
          while (i < 30)
          {
            localObject1 = new StringBuilder();
            ((StringBuilder)localObject1).append(paramAnonymousView);
            ((StringBuilder)localObject1).append(str.charAt(i));
            paramAnonymousView = ((StringBuilder)localObject1).toString();
            i += 1;
          }
          if (((String)localObject2).equals("c2N0ZntXM2xjMG1l"))
          {
            localObject1 = new Intent();
            ((Intent)localObject1).putExtra("data_return", paramAnonymousView);
            s.this.setResult(-1, (Intent)localObject1);
            s.this.finish();
            return;
          }
          Toast.makeText(s.this.getApplicationContext(), "something wrong", 1).show();
          return;
      }
      Toast.makeText(s.this.getApplicationContext(), "something wrong", 1).show();
      }
    });
}

c2N0ZntXM2xjMG1l base64解密得到前半flag sctf{W3lc0me

protected void onActivityResult(int paramInt1, int paramInt2, Intent paramIntent)
{
    TextView localTextView = (TextView)findViewById(2131165323);
    Button localButton = (Button)findViewById(2131165219);
    if (paramInt1 != 1) {
      return;
    }
    if (paramInt2 == -1)
    {
      Object localObject1 = "";
      try
      {
      Object localObject2 = MessageDigest.getInstance("MD5");
      ((MessageDigest)localObject2).update("syclover".getBytes());
      localObject2 = new BigInteger(1, ((MessageDigest)localObject2).digest()).toString(16);
      localObject1 = localObject2;
      }
      catch (Exception localException)
      {
      localException.printStackTrace();
      }
      if (f.encode(paramIntent.getStringExtra("data_return"), (String)localObject1).equals("~8t808_8A8n848r808i8d8-8w808r8l8d8}8"))
      {
      localTextView.setVisibility(0);
      localButton.setVisibility(4);
      }
      else
      {
      Toast.makeText(getApplicationContext(), "one more step", 1).show();
      }
    }}
public static String encode(String paramString1, String paramString2)
{
    int j = paramString1.length();
    int k = paramString2.length();
    StringBuilder localStringBuilder = new StringBuilder();
    int i = 0;
    while (i < j)
    {
      localStringBuilder.append(paramString1.charAt(i));
      localStringBuilder.append(paramString2.charAt(i / k));
      i += 1;
    }
    return localStringBuilder.toString();
}

~8t808_8A8n848r808i8d8-8w808r8l8d8}8取奇数得到后半flag。
最终sctf{W3lc0me~t0_An4r0id-w0rld}


creakme

ida阅读代码
int sub_402540()
{
HMODULE v0; // eax
int v1; // eax
_DWORD *v2; // eax
unsigned int ser_len; // edx
_DWORD *string; // ecx
unsigned int string_len; // ebx
char *ascc; // edi
unsigned int v7; // esi
unsigned int v8; // esi
bool v9; // cf
unsigned __int8 v10; // al
unsigned __int8 v11; // al
unsigned __int8 v12; // al
signed int v13; // esi
_BYTE *v14; // ecx
_BYTE *v15; // ecx
const char *v16; // edx
int v17; // eax
void *Memory; //
int v20; //
unsigned int v21; //
void *Dst; //
int v23; //
unsigned int v24; //
char Src; //
int v26; //

v0 = GetModuleHandleW(0);
sub_402320(v0);
sub_4024A0();
v1 = sub_402870(std::cout, "welcome to 2019 sctf");
std::basic_ostream<char,std::char_traits<char>>::operator<<(v1, sub_402AC0);
sub_402870(std::cout, "please input your ticket:");
sub_402AF0(std::cin, &Src);
v23 = 0;
v24 = 15;
LOBYTE(Dst) = 0;
sub_401D30(&Dst, &Src, strlen(&Src));
v26 = 0;
v2 = aes(&Memory, (int)&Dst);
ser_len = strlen(aPvfqyc4ttc2uxr);
string = v2;
if ( v2 >= 16u )
    string = (_DWORD *)*v2;
string_len = v2;
ascc = aPvfqyc4ttc2uxr;
v7 = v2;
if ( ser_len < string_len )
    v7 = ser_len;
v9 = v7 < 4;                                  // len - 4
v8 = v7 - 4;
if ( v9 )
{
LABEL_8:
    if ( v8 == -4 )
      goto LABEL_17;
}
else
{
    while ( *string == *(_DWORD *)ascc )
    {
      ++string;                                 // +=4
      ascc += 4;
      v9 = v8 < 4;
      v8 -= 4;
      if ( v9 )
      goto LABEL_8;
    }
}
v9 = *(_BYTE *)string < (unsigned __int8)*ascc;
if ( *(_BYTE *)string != *ascc
    || v8 != -3
    && ((v10 = *((_BYTE *)string + 1), v9 = v10 < (unsigned __int8)ascc, v10 != ascc)
   || v8 != -2
   && ((v11 = *((_BYTE *)string + 2), v9 = v11 < (unsigned __int8)ascc, v11 != ascc)
      || v8 != -1 && (v12 = *((_BYTE *)string + 3), v9 = v12 < (unsigned __int8)ascc, v12 != ascc))) )
{
    v13 = -v9 | 1;
    goto LABEL_18;
}
LABEL_17:
v13 = 0;
LABEL_18:
if ( !v13 )                                 // v13要为0
{
    if ( ser_len <= string_len )
      v13 = ser_len < string_len;
    else
      v13 = -1;
}
if ( v21 >= 0x10 )
{
    v14 = Memory;
    if ( v21 + 1 >= 0x1000 )
    {
      v14 = (_BYTE *)*((_DWORD *)Memory - 1);
      if ( (unsigned int)((_BYTE *)Memory - v14 - 4) > 0x1F )
      invalid_parameter_noinfo_noreturn(v14, v21 + 36);
    }
    frees(v14);
}
v26 = -1;
v20 = 0;
v21 = 15;
LOBYTE(Memory) = 0;
if ( v24 >= 0x10 )
{
    v15 = Dst;
    if ( v24 + 1 >= 0x1000 )
    {
      v15 = (_BYTE *)*((_DWORD *)Dst - 1);
      if ( (unsigned int)((_BYTE *)Dst - v15 - 4) > 0x1F )
      invalid_parameter_noinfo_noreturn(v15, v24 + 36);
    }
    frees(v15);
}
v16 = "Have fun!";
if ( v13 )
    v16 = "A forged ticket!!";
v17 = sub_402870(std::cout, v16);
std::basic_ostream<char,std::char_traits<char>>::operator<<(v17, sub_402AC0);
system("pause");
return 0;
}

查看sub_402320函数的代码发现
void __thiscall sub_402320(_DWORD *this)
{
int v1; // eax
__int16 v2; // bx
const char *v3; // esi
signed int i; // edi
int v5; // eax

v1 = this;
v2 = *(_WORD *)((char *)this + v1 + 6);
v3 = (char *)this + v1 + 248;
for ( i = 0; i < v2; ++i )                  // 判断区段
{
    v5 = strcmp(v3, ".SCTF");
    if ( v5 )
      v5 = -(v5 < 0) | 1;
    if ( !v5 )
    {
      DebugBreak();
      return;
    }
    v3 += 40;
}
}
读取区段,判断区段是否是.SCTF区段。
如果是,就会跳到loc_4023EF并在里边调用函数解密区段。
.text:004023EF loc_4023EF:                           ; DATA XREF: .rdata:stru_407B58↓o
.text:004023EF               mov   esp,
.text:004023F2               lea   eax,
.text:004023F5               push    eax             ; pbDebuggerPresent
.text:004023F6               call    ds:GetCurrentProcess
.text:004023FC               push    eax             ; hProcess
.text:004023FD               call    ds:CheckRemoteDebuggerPresent
.text:00402403               call    ds:IsDebuggerPresent
.text:00402409               test    eax, eax
.text:0040240B               jnz   short loc_4023B9
.text:0040240D               cmp   , eax
.text:00402410               jnz   short loc_4023B9
.text:00402412               mov   eax,
.text:00402415               mov   edx,
.text:00402418               mov   ecx,
.text:0040241B               add   ecx,
.text:0040241E               mov   esi,
.text:00402421               lea   edi,
.text:00402424
.text:00402424 loc_402424:                           ; CODE XREF: sub_402320+109↓j
.text:00402424               mov   al,        ; sycloversyclover
.text:00402426               inc   esi
.text:00402427               test    al, al
.text:00402429               jnz   short loc_402424 ; sycloversyclover
.text:0040242B               sub   esi, edi
.text:0040242D               push    esi
.text:0040242E               push    ecx
.text:0040242F               call    sub_402450
.text:00402434               add   esp, 8
.text:00402437               jmp   short loc_4023B9
.text:00402439 ; ---------------------------------------------------------------------------
.text:00402439
.text:00402439 loc_402439:                           ; CODE XREF: sub_402320+8A↑j
.text:00402439               add   esi, 28h
.text:0040243C               inc   edi
.text:0040243D               jmp   loc_402372
.text:0040243D sub_402320      endp

在sub_4024A0函数中,会进入.SCTF区段。
主要是解密>pvfqYc,4tTc2UxRmlJ,sB{Fh4Ck2:CFOb4ErhtIcoLo
解密成nKnbHsgqD3aNEB91jB3gEzAr+IklQwT1bSs3+bXpeuo=

sub_4020D0函数其实就是AES加密。

CBC模式,密码为sycloversyclover,偏移量为sctfsctfsctfsctf。

最终得到




Bybare

一道游戏题,总共有三关。
第一关,
.text:00005593B1D94798 main:                                 ; DATA XREF: start+1D↑o
.text:00005593B1D94798 ; __unwind {
.text:00005593B1D94798               push    rbp
.text:00005593B1D94799               mov   rbp, rsp
.text:00005593B1D9479C               sub   rsp, 160h
.text:00005593B1D947A3               mov   rax, fs:28h
.text:00005593B1D947AC               mov   , rax
.text:00005593B1D947B0               xor   eax, eax
.text:00005593B1D947B2               mov   dword ptr , 0
.text:00005593B1D947BC               mov   qword ptr , 0
.text:00005593B1D947C7               mov   qword ptr , 0
.text:00005593B1D947D2               mov   qword ptr , 0
.text:00005593B1D947DD               mov   byte ptr , 0
.text:00005593B1D947E4               mov   qword ptr , 0
.text:00005593B1D947EF               mov   qword ptr , 0
.text:00005593B1D947FA               mov   qword ptr , 0
.text:00005593B1D94805               mov   byte ptr , 0
.text:00005593B1D9480C               mov   qword ptr , 0
.text:00005593B1D94817               mov   qword ptr , 0
.text:00005593B1D94822               mov   qword ptr , 0
.text:00005593B1D9482D               mov   qword ptr , 0
.text:00005593B1D94838               mov   qword ptr , 0
.text:00005593B1D94843               mov   qword ptr , 0
.text:00005593B1D9484E               mov   word ptr , 0
.text:00005593B1D94857               mov   rax, '********'
.text:00005593B1D94861               mov   rdx, '*.******'
.text:00005593B1D9486B               mov   , rax
.text:00005593B1D94872               mov   , rdx
.text:00005593B1D94879               mov   rax, '.s**.***'
.text:00005593B1D94883               mov   rdx, '****..*.'
.text:00005593B1D9488D               mov   , rax
.text:00005593B1D94891               mov   , rdx
.text:00005593B1D94895               mov   rax, '.****.**'
.text:00005593B1D9489F               mov   rdx, '********'
.text:00005593B1D948A9               mov   , rax
.text:00005593B1D948AD               mov   , rdx
.text:00005593B1D948B1               mov   rax, '***..***'
.text:00005593B1D948BB               mov   rdx, '*#..**..'
.text:00005593B1D948C5               mov   , rax
.text:00005593B1D948C9               mov   , rdx
.text:00005593B1D948CD               mov   rax, '*..***..'
.text:00005593B1D948D7               mov   rdx, '*****.**'
.text:00005593B1D948E1               mov   , rax
.text:00005593B1D948E5               mov   , rdx
.text:00005593B1D948E9               mov   rax, '********'
.text:00005593B1D948F3               mov   rdx, '.*******'
.text:00005593B1D948FD               mov   , rax
.text:00005593B1D94901               mov   , rdx
.text:00005593B1D94905               mov   rax, '****..**'
.text:00005593B1D9490F               mov   rdx, '.**..***'
.text:00005593B1D94919               mov   , rax
.text:00005593B1D9491D               mov   , rdx
.text:00005593B1D94921               mov   rax, '*.*..*..'
.text:00005593B1D9492B               mov   , rax
.text:00005593B1D9492F               mov   dword ptr , '.**.'
.text:00005593B1D94936               mov   word ptr , 2Ah ; '*'
.text:00005593B1D9493C               mov   qword ptr , 0
.text:00005593B1D94947               mov   qword ptr , 0
.text:00005593B1D94952               mov   dword ptr , 0
.text:00005593B1D9495C               lea   rax,
.text:00005593B1D94963               add   rax, 16h
.text:00005593B1D94967               mov   , rax
.text:00005593B1D9496E               mov   rax, '019_ftcs' ; sctf_019
.text:00005593B1D94978               mov   , rax
.text:00005593B1D9497F               mov   word ptr , 32h ; '2' ; sctf_2019
.text:00005593B1D94988               xor   rax, rax
.text:00005593B1D9498B               jb      short loc_5593B1D94990
.text:00005593B1D9498D               jnb   short loc_5593B1D94990
.text:00005593B1D9498D ; ---------------------------------------------------------------------------
.text:00005593B1D9498F               db 0E1h
.text:00005593B1D94990 ; ---------------------------------------------------------------------------
.text:00005593B1D94990
.text:00005593B1D94990 loc_5593B1D94990:                     ; CODE XREF: .text:00005593B1D9498B↑j
.text:00005593B1D94990                                       ; .text:00005593B1D9498D↑j
.text:00005593B1D94990               lea   rdi, aPlzTellMeTheSh ; "plz tell me the shortest password1:"
.text:00005593B1D94997               call    _puts
.text:00005593B1D9499C               lea   rax,
.text:00005593B1D949A3               mov   rsi, rax
.text:00005593B1D949A6               lea   rdi, aS         ; "%s"
.text:00005593B1D949AD               mov   eax, 0
.text:00005593B1D949B2               call    _scanf
.text:00005593B1D949B7               mov   dword ptr , 1
.text:00005593B1D949C1
.text:00005593B1D949C1 loc_5593B1D949C1:                     ; CODE XREF: .text:00005593B1D94A9F↓j
.text:00005593B1D949C1               cmp   dword ptr , 0
.text:00005593B1D949C8               jz      loc_5593B1D94AB1
.text:00005593B1D949CE               mov   eax,
.text:00005593B1D949D4               cdqe
.text:00005593B1D949D6
.text:00005593B1D949D6 loc_5593B1D949D6:
.text:00005593B1D949D6               lea   rdx,
.text:00005593B1D949DD               add   rax, rdx
.text:00005593B1D949E0               movzx   eax, byte ptr
.text:00005593B1D949E3               mov   , al
.text:00005593B1D949E9               cmp   byte ptr , 77h ; 'w'
.text:00005593B1D949F0               jnz   short loc_5593B1D949FC
.text:00005593B1D949F2               sub   qword ptr , 5
.text:00005593B1D949FA               jmp   short loc_5593B1D94A66
.text:00005593B1D949FC ; ---------------------------------------------------------------------------
.text:00005593B1D949FC
.text:00005593B1D949FC loc_5593B1D949FC:                     ; CODE XREF: .text:00005593B1D949F0↑j
.text:00005593B1D949FC               cmp   byte ptr , 73h ; 's'
.text:00005593B1D94A03               jnz   short loc_5593B1D94A0F
.text:00005593B1D94A05               add   qword ptr , 5
.text:00005593B1D94A0D               jmp   short loc_5593B1D94A66
.text:00005593B1D94A0F ; ---------------------------------------------------------------------------
.text:00005593B1D94A0F
.text:00005593B1D94A0F loc_5593B1D94A0F:                     ; CODE XREF: .text:00005593B1D94A03↑j
.text:00005593B1D94A0F               cmp   byte ptr , 64h ; 'd'
.text:00005593B1D94A16               jnz   short loc_5593B1D94A22
.text:00005593B1D94A18               add   qword ptr , 1
.text:00005593B1D94A20               jmp   short loc_5593B1D94A66
.text:00005593B1D94A22 ; ---------------------------------------------------------------------------
.text:00005593B1D94A22
.text:00005593B1D94A22 loc_5593B1D94A22:                     ; CODE XREF: .text:00005593B1D94A16↑j
.text:00005593B1D94A22               cmp   byte ptr , 61h ; 'a'
.text:00005593B1D94A29               jnz   short loc_5593B1D94A35
.text:00005593B1D94A2B               sub   qword ptr , 1
.text:00005593B1D94A33               jmp   short loc_5593B1D94A66
.text:00005593B1D94A35 ; ---------------------------------------------------------------------------
.text:00005593B1D94A35
.text:00005593B1D94A35 loc_5593B1D94A35:                     ; CODE XREF: .text:00005593B1D94A29↑j
.text:00005593B1D94A35               cmp   byte ptr , 78h ; 'x'
.text:00005593B1D94A3C               jnz   short loc_5593B1D94A48
.text:00005593B1D94A3E               add   qword ptr , 19h
.text:00005593B1D94A46               jmp   short loc_5593B1D94A66
.text:00005593B1D94A48 ; ---------------------------------------------------------------------------
.text:00005593B1D94A48
.text:00005593B1D94A48 loc_5593B1D94A48:                     ; CODE XREF: .text:00005593B1D94A3C↑j
.text:00005593B1D94A48               cmp   byte ptr , 79h ; 'y'
.text:00005593B1D94A4F               jnz   short loc_5593B1D94A5B
.text:00005593B1D94A51               sub   qword ptr , 19h
.text:00005593B1D94A59               jmp   short loc_5593B1D94A66
.text:00005593B1D94A5B ; ---------------------------------------------------------------------------
.text:00005593B1D94A5B
.text:00005593B1D94A5B loc_5593B1D94A5B:                     ; CODE XREF: .text:00005593B1D94A4F↑j
.text:00005593B1D94A5B               mov   dword ptr , 0
.text:00005593B1D94A65               nop
.text:00005593B1D94A66
.text:00005593B1D94A66 loc_5593B1D94A66:                     ; CODE XREF: .text:00005593B1D949FA↑j
.text:00005593B1D94A66                                       ; .text:00005593B1D94A0D↑j ...
.text:00005593B1D94A66               add   dword ptr , 1
.text:00005593B1D94A6D               mov   rax,
.text:00005593B1D94A74               movzx   eax, byte ptr
.text:00005593B1D94A77               cmp   al, 2Eh ; '.'
.text:00005593B1D94A79               jz      short loc_5593B1D94A93
.text:00005593B1D94A7B               mov   rax,
.text:00005593B1D94A82               movzx   eax, byte ptr
.text:00005593B1D94A85               cmp   al, 23h ; '#'
.text:00005593B1D94A87               jz      short loc_5593B1D94A93
.text:00005593B1D94A89               mov   dword ptr , 0
.text:00005593B1D94A93
.text:00005593B1D94A93 loc_5593B1D94A93:                     ; CODE XREF: .text:00005593B1D94A79↑j
.text:00005593B1D94A93                                       ; .text:00005593B1D94A87↑j
.text:00005593B1D94A93               mov   rax,
.text:00005593B1D94A9A               movzx   eax, byte ptr
.text:00005593B1D94A9D               cmp   al, 23h ; '#'
.text:00005593B1D94A9F               jnz   loc_5593B1D949C1
.text:00005593B1D94AA5               lea   rdi, aGoodYouFindThe ; "good!you find the right way!\nBut there"...
.text:00005593B1D94AAC               call    _puts
.text:00005593B1D94AB1
.text:00005593B1D94AB1 loc_5593B1D94AB1:                     ; CODE XREF: .text:00005593B1D949C8↑j
.text:00005593B1D94AB1               cmp   dword ptr , 0
.text:00005593B1D94AB8               jnz   short loc_5593B1D94AD5
.text:00005593B1D94ABA               lea   rdi, aSorryIsTNotARi ; "sorry,is't not a right way..."
.text:00005593B1D94AC1               mov   eax, 0
.text:00005593B1D94AC6               call    _printf
.text:00005593B1D94ACB               mov   eax, 0
.text:00005593B1D94AD0               jmp   loc_5593B1D94C0C

先赋值迷宫,总共六个控制键,好像是三维的,但是可以化成一维。

w/s分别为后退/前进五格,a/d分别为后退/前进一格,y/x分别为后退/前进25格。

把迷宫换成一维,最终要使s和#相遇。
**************.****.**s..*..******.****.***********..***..**..#*..***..***.*****

得到sxss

第二关。
输入字符进入进入函数,最终和sctf_9102对比。
汇编看起来比较麻烦,不能f5的原因是中间多了一个0XE4字节,可以手动nop掉。
.text:0000000000000E11               jnb   short loc_E14
.text:0000000000000E11 ; ---------------------------------------------------------------------------
.text:0000000000000E13               db 0E4h
.text:0000000000000E14 ; ---------------------------------------------------------------------------
.text:0000000000000E14
.text:0000000000000E14 loc_E14:                              ; CODE XREF: .text:0000000000000E0F↑j
.text:0000000000000E14                                       ; .text:0000000000000E11↑j
.text:0000000000000E14               mov   dword ptr , 0
.text:0000000000000E1E
.text:0000000000000E1E loc_E1E:                              ; CODE XREF: .text:0000000000000F4B↓j
.text:0000000000000E1E               cmp   dword ptr , 0

nop之后
unsigned __int64 __fastcall sub_C22(const char *a1, __int64 a2)
{
bool v2; // al
int v3; // eax
int v4; // eax
int v5; // eax
int v7; //
signed int v8; //
int v9; //
int v10; //
int v11; //
int v12; //
int v13; //
char *v14; //
int v15; //
unsigned __int64 v16; //

v16 = __readfsqword(0x28u);
qmemcpy(v15, &off_1740, 0x200uLL);
v8 = 3;
v7 = 0;
v10 = 0;
v11 = 0;
v12 = strlen(a1);
v14 = (char *)a1;
while ( 1 )
{
    v13 = 0;
    if ( v10 < v12 )
      break;
LABEL_13:
    if ( v10 >= v12 )
      goto LABEL_14;
}
do
{
    if ( a1 != 25 )
      break;
    ++v10;
    ++v13;
}
while ( v10 < v12 );
if ( v10 != v12 )
{
    if ( v12 - v10 > 1 )
    {
      v2 = v10 == 19 && a1 == 16;
      a1;
    }
    ++v10;
    goto LABEL_13;
}
LABEL_14:
v9 = 0;
while ( v12 > 0 )
{
    v8 -= v15[*v14] == 64;
    v7 = v15[*v14] & 0x3F | (v7 << 6);
    if ( ++v9 == 4 )
    {
      v9 = 0;
      if ( v8 )
      {
      v3 = v11++;
      *(_BYTE *)(v3 + a2) = BYTE2(v7);
      }
      if ( v8 > 1 )
      {
      v4 = v11++;
      *(_BYTE *)(v4 + a2) = BYTE1(v7);
      }
      if ( v8 > 2 )
      {
      v5 = v11++;
      *(_BYTE *)(v5 + a2) = v7;
      }
    }
    ++v14;
    --v12;
}
return __readfsqword(0x28u) ^ v16;
}

其实这代码的原理就是,输入字符分成四个一组,每次取8位二进制索引字符,取字符低6位,一组可以得到4个6位二进制,最终一组得到3个字符。

可以逆推得到password2:c2N0Zl85MTAy

第三关。
signed __int64 __fastcall sub_5593B1D94FFA(char *a1)
{
int v1; // ST24_4
int v2; // ST28_4
int v3; // ST2C_4
signed int v5; //
signed int i; //
int cout; //
int v8; //
int v9; //
int v10; //
unsigned int v11; //
unsigned __int64 v12; //

v12 = __readfsqword(0x28u);
v8 = 0xBE;
v8 = '\x04';
v8 = '\x06';
v8 = 0x80;
v8 = 0xC5;
v8 = 0xAF;
v8 = 0x76;
v8 = 0x47;
v8 = 0x9F;
v8 = 0xCC;
v8 = 0x40;
v8 = 0x1F;
v8 = 0xD8;
v8 = 0xBF;
v8 = 0x92;
v8 = 0xEF;
v1 = (a1 << 8) | (a1 << 16) | (a1 << 24) | a1;
v2 = (a1 << 8) | (a1 << 16) | (a1 << 24) | a1;
v3 = (a1 << 8) | (a1 << 16) | (a1 << 24) | a1;// 16位
cout = 0;
v5 = 4;
v10 = byteswap_ulong((a1 << 8) | (a1 << 16) | (*a1 << 24) | (unsigned int)a1);// 颠倒过来排列
v10 = byteswap_ulong(v1);
v10 = byteswap_ulong(v2);
v10 = byteswap_ulong(v3);
do
{
    v10 = sub_5593B1D9543B(v10, v10, v10, v10);
    ++cout;
    ++v5;
}
while ( v5 <= 29 );
v9 = (unsigned int)v10 >> 24;
v9 = BYTE2(v10);
v9 = BYTE1(v10);
v9 = LOBYTE(v10);
v9 = (unsigned int)v10 >> 24;
v9 = BYTE2(v10);
v9 = BYTE1(v10);
v9 = LOBYTE(v10);
v9 = (unsigned int)v10 >> 24;
v9 = BYTE2(v10);
v9 = BYTE1(v10);
v9 = LOBYTE(v10);
v9 = v11 >> 24;
v9 = BYTE2(v11);
v9 = BYTE1(v11);
v9 = (unsigned __int8)v11;
for ( i = 0; i <= 15; ++i )
{
    if ( v9 != v8 )
      return 0xFFFFFFFFLL;
}
return 1LL;
}

__int64 __fastcall sub_5593B1D9543B(int a1, int a2, int a3, unsigned int a4)
{
return a1 ^ (unsigned int)sub_5593B1D95464(a2 ^ a3 ^ a4);
}
__int64 __fastcall sub_5593B1D95464(unsigned int a1)
{
int v1; // ST18_4
int v3; //
unsigned __int64 v4; //

v4 = __readfsqword(0x28u);
qmemcpy(v3, &byte_5593B1D95940, 1152uLL);
v1 = (v3 << 16) | v3[(unsigned __int8)a1] | (v3 << 8) | (v3 << 24);
return __ROL4__(v1, 12) ^ (unsigned int)(__ROL4__(v1, 8) ^ __ROR4__(v1, 2)) ^ __ROR4__(v1, 6);
}

输入字符,长度为16,分为四位一组,组成4个int元素,再大小端颠倒。然后第2,3,4元素异或进入函数索引字符再循环异或再跟第一个元素异或得到第五个元素,再用2,3,4,5重复相同步骤得到第六个元素,以此类推。
循环26次,取最高四个元素跟程序的值对比,可以写脚本逆推。
i=

asc =

def xors(xor_mix):
    temp1 = (xor_mix >> 24)&0xff
    temp2 = (xor_mix >> 16)&0xff
    temp3 = (xor_mix >> 8)&0xff
    temp = (xor_mix)&0xff

    temp_q = asc | (asc<<24)|(asc<<16)|(asc<<8)
    print ("%x"%(temp_q))
    temp_i = ((temp_q <<12|temp_q>>20)&0xffffffff) ^ ((temp_q <<8|temp_q>>24)&0xffffffff) ^ ((temp_q>>2|temp_q<<30)&0xffffffff)^((temp_q>>6|temp_q<<26)&0xffffffff)
    return temp_i

print ("%x"%(xors(0x6011F432)))
print (len(asc))

for q in range(26):
    i.append(i^xors(i^i^i))

print (i)
print ("%x"%(i[-1]))
print ("%x"%(i[-2]))
print ("%x"%(i[-3]))
print ("%x"%(i[-4]))
# fl4g_is_s0_ug1y!


得到fl4g_is_s0_ug1y!




music

app打开需要联网,不懂为啥。
查看代码
package com.example.music;

import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

public class q
{
private h h;
private Context mycontext;

public q(Context paramContext)
{
    this.mycontext = paramContext;
}

public String get()
{
    String str1 = null;
    this.h = new h(this.mycontext, "sctf.db", null, 1);
    Cursor localCursor = this.h.getWritableDatabase().query("SYC", null, null, null, null, null, null);
    if (localCursor.moveToFirst()) {
      do
      {
      str1 = localCursor.getString(localCursor.getColumnIndex("S1"));
      String str2 = localCursor.getString(localCursor.getColumnIndex("S2"));
      StringBuilder localStringBuilder = new StringBuilder();
      localStringBuilder.append(str1);
      localStringBuilder.append(str2);
      str1 = localStringBuilder.toString();
      } while (localCursor.moveToNext());
    }
    localCursor.close();
    return str1;
}
}

发现程序里边有.db文件,用SQLiteSpy打开。


得到hellosctf
package com.example.music;

import java.security.MessageDigest;

public class a
{
public String a(String paramString)
{
    return b(paramString);
}

public String b(String paramString)
{
    new p();
    if (paramString != null) {
      try
      {
      paramString = p.a(MessageDigest.getInstance("MD5").digest(paramString.getBytes()));
      return paramString;
      }
      catch (Exception paramString)
      {
      paramString.printStackTrace();
      }
    }
    return null;
}
}

package com.example.music;

public class p
{
public static String a(byte[] paramArrayOfByte)
{
    StringBuffer localStringBuffer = new StringBuffer();
    int i = 0;
    while (i < paramArrayOfByte.length)
    {
      String str = Integer.toHexString(paramArrayOfByte & 0xFF);
      Object localObject = str;
      if (str.length() == 1)
      {
      localObject = new StringBuilder();
      ((StringBuilder)localObject).append('0');
      ((StringBuilder)localObject).append(str);
      localObject = ((StringBuilder)localObject).toString();
      }
      localStringBuffer.append(((String)localObject).toUpperCase());
      i += 1;
    }
    return localStringBuffer.toString();
}
}

字母变大写,得到E7E64BF658BAB14A25C9D67A054CEBE5
然后和输入字符进入加密。
package com.example.music;

public class c
{
private static int m = 256;

public String a(String paramString1, String paramString2)
{
    int i = m;
    int[] arrayOfInt = new int;
    byte[] arrayOfByte = new byte;
    i = 0;
    while (i < m)
    {
      arrayOfInt = i;
      arrayOfByte = ((byte)paramString2.charAt(i % paramString2.length()));
      i += 1;
    }
    i = 0;
    int j = 0;
    for (;;)
    {
      k = m;
      if (i >= k - 1) {
      break;
      }
      j = (arrayOfInt + j + arrayOfByte) % k;
      k = arrayOfInt;
      arrayOfInt = arrayOfInt;
      arrayOfInt = k;
      i += 1;
    }
    paramString2 = paramString1.toCharArray();
    paramString1 = new char;
    int k = 0;
    j = 0;
    i = 0;
    while (i < paramString2.length)
    {
      int n = m;
      k = (k + 1) % n;
      j = (arrayOfInt + j) % n;
      int i1 = arrayOfInt;
      arrayOfInt = arrayOfInt;
      arrayOfInt = i1;
      i1 = arrayOfInt;
      int i2 = arrayOfInt;
      paramString1 = ((char)(paramString2 - k ^ (char)arrayOfInt[((i1 + i2 % n) % n)]));
      i += 1;
    }
    new p();
    return p.a(new String(paramString1).getBytes());
}
}

看起来是变种RC4

最终对比
    public boolean g(String paramString)
    {
      return paramString.equals(s.this.getApplicationContext().getResources().getString(2131492904));
    }

没动态调试环境,一直调试不了,后来发现应该是储存在Strings.xml文件里边。
    <string name="cipher">C28BC39DC3A6C283C2B3C39DC293C289C2B8C3BAC29EC3A0C3A7C29A1654C3AF28C3A1C2B1215B53</string>
    <string name="local">/data/data/com.example.music/databases/</string>
    <string name="no">wrong!</string>
    <string name="search_menu_title">Search</string>
    <string name="song">http://www.ytmp3.cn/down/44093.mp3</string>
得到密文,看到一个网址,应该是需要联网的原因,程序开始需要听一段音乐,音乐应该就是这个网址里边的。

密文是经过大写变换的,变成小写可以得到c28bc39dc3a6c283c2b3c39dc293c289c2b8c3bac29ec3a0c3a7c29a1654c3af28c3a1c2b1215b53

但是即使这样,用python写脚本一直写不通.
import base64
flag = "c28bc39dc3a6c283c2b3c39dc293c289c2b8c3bac29ec3a0c3a7c29a1654c3af28c3a1c2b1215b53"
flagh = []
for q in range(0,len(flag),2):
      flagh.append(int(flag,16))

print flagh

S = []
T = []
key = "E7E64BF658BAB14A25C9D67A054CEBE5"

# C28BC39DC3A6C283C2B3C39DC293C289C2B8C3BAC29EC3A0C3A7C29A1654C3AF28C3A1C2B1215B53
# c28bc39dc3a6c283c2b3c39dc293c289c2b8c3bac29ec3a0c3a7c29a1654c3af28c3a1c2b1215b53
for i in range(256):
    S.append(i)
    T.append(key)

#print S
#print T

j = 0
for i in range(256):
    j = (j+S+ord(T))%256

    S,S=S,S

i = 0
j = 0
k = []
# for r in range(len(flag)):
#         i = (i+1)%256
#         j = (j+S)%256
#         S,S = S,S
#         t = (S+S)%256
#         k.append(S)
#         
flags = []
for r in range(len(flagh)):
      i = (i+1)%256
      j = (j+S)%256
      S,S = S,S
      t = (S+S)%256
      k.append(S)
      flags.append((flagh ^ S[(S + S % 256) % 256]) + i)

print flags

后来发现先知社区有大佬写wp了。
引用他们的脚本
https://xz.aliyun.com/t/5478#toc-21
public class Notepad
{
    public static void main(String[] args)
    {
      byte[] enctob = new byte[]{-62, -117, -61, -99, -61, -90, -62, -125, -62, -77, -61, -99, -62, -109, -62, -119, -62, -72, -61, -70, -62, -98, -61, -96, -61, -89, -62, -102, 22, 84, -61, -81, 40, -61, -95, -62, -79, 33, 91, 83};      
      String bs = new String(enctob);
      char[] flagenc = bs.toCharArray();
      char[] out = new char;
      int[] S = new int;
      byte[] wtf = new byte;
      int i,j,k;
      String key = "E7E64BF658BAB14A25C9D67A054CEBE5";
      for (i = 0; i < 256; i++ )
      {
            S = i;
            wtf = (byte)(key.charAt(i % 32));
      }
      i = 0;
      j = 0;
      for(i = 0,j = 0;i < 256; i++ )
      {
            j = (S + j + wtf) % 256;
            k = S;
            S = S;
            S = k;
      }
      for (i = 0,j = 0,k = 0; i < bs.length(); i++ )
      {
            k = (k + 1) % 256;
            j = (S + j) % 256;
            int temp = S;
            S = S;
            S = temp;
            out = (char)((flagenc ^ S[(S + S % 256) % 256]) + k);
            System.out.println(out);
      }

    }
}
得到flag

他们中出现了两句
String bs = new String(enctob);
      char[] flagenc = bs.toCharArray();
可能是编码问题,这个问题有待解决

0xEASONs 发表于 2019-6-25 19:49

编码问题是因为一个字符getByte是两个

瑟瑟发抖小菜虾 发表于 2019-6-24 21:25

大佬写的博客太好了。。。。。 想前排请问一下大佬 第一个题的脚本有没有 别的方法(感觉这个有点麻烦鸭)

姚小宝 发表于 2019-6-25 00:03

瑟瑟发抖小菜虾 发表于 2019-6-24 21:25
大佬写的博客太好了。。。。。 想前排请问一下大佬 第一个题的脚本有没有 别的方法(感觉这个有点麻烦鸭)

应该有吧,只不过我对安卓平台接触不多不知道。

0xEASONs 发表于 2019-6-25 20:32

https://i.imgur.com/3bFW2nl.jpg

Hotspur 发表于 2019-6-26 17:22

本帖最后由 Hotspur 于 2019-6-26 17:30 编辑

膜拜大佬,当时babyre那题卡在最后一步半天没做出来。。。
第二步其实是个base64解密。。不过要多输入一个‘=’。。当时把最后一位是’=‘推出来后直接想到base,一解密还真成了。

姚小宝 发表于 2019-6-26 17:31

Hotspur 发表于 2019-6-26 17:22
膜拜大佬,当时babyre那题卡在最后一步半天没做出来。。。
第二步其实是个base64解密。。不过要多输入一个 ...

嗯,就是base64解密,还原之后才反映过来
页: [1]
查看完整版本: 2019SCTF 部分WP