攻防世界mobile新手区之app2 write up

0x00拖进模拟器查看:

0x01上dex2jar:

查看MainActivity.class:

package com.tencent.testvuln;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import com.tencent.testvuln.c.SignatureTool;

@SuppressLint({"ShowToast"})
public class MainActivity extends Activity implements View.OnClickListener {
  private Button a;
  
  private Handler b = null;
  
  private EditText c;
  
  private EditText d;
  
  public void onClick(View paramView) {
    switch (paramView.getId()) {
      default:
        return;
      case 2131165187:
        break;
    } 
    if (this.c.getText().length() == 0 || this.d.getText().length() == 0) {
      Toast.makeText((Context)this, ", 1).show();
      return;
    } 
    String str1 = this.c.getText().toString();
    String str2 = this.d.getText().toString();
    Log.e("test", str1 + " test2 = " + str2);
    Intent intent = new Intent((Context)this, SecondActivity.class);
    intent.putExtra("ili", str1);
    intent.putExtra("lil", str2);
    startActivity(intent);
  }
  
  protected void onCreate(Bundle paramBundle) {
    super.onCreate(paramBundle);
    setContentView(2130903040);
    this.a = (Button)findViewById(2131165187);
    this.a.setOnClickListener(this);
    this.c = (EditText)findViewById(2131165185);
    this.d = (EditText)findViewById(2131165186);
    SharedPreferences.Editor editor = getSharedPreferences("test", 0).edit();
    editor.putLong("ili", System.currentTimeMillis());
    editor.commit();
    Log.d("hashcode", SignatureTool.getSignature((Context)this) + "");
  }
  
  public boolean onCreateOptionsMenu(Menu paramMenu) {
    getMenuInflater().inflate(2131099648, paramMenu);
    return true;
  }
  
  public boolean onOptionsItemSelected(MenuItem paramMenuItem) { return (paramMenuItem.getItemId() == 2131165188) ? true : super.onOptionsItemSelected(paramMenuItem); }
}

我们查看onclick方法:

public void onClick(View paramView) {
    switch (paramView.getId()) {
      default:
        return;
      case 2131165187:
        break;
    } 
  //c和d分别是两个输入框
//获取两个输入框的内容后做是否为空校验
    if (this.c.getText().length() == 0 || this.d.getText().length() == 0) {
      Toast.makeText((Context)this, ", 1).show();
      return;
    } 
    String str1 = this.c.getText().toString();
    String str2 = this.d.getText().toString();
    Log.e("test", str1 + " test2 = " + str2);
//空校验通过,通过startActivity()启动一个新的activity:SecondActivity
    Intent intent = new Intent((Context)this, SecondActivity.class);
    intent.putExtra("ili", str1);
    intent.putExtra("lil", str2);
    startActivity(intent);
  }

一波分析之后我们查看SecondActivity.class:,同时注意,SecondActivity初始化之后带入两个参数ili和lli,ili是变量c,lli是d。

package com.tencent.testvuln;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
import com.tencent.testvuln.c.Encryto;

public class SecondActivity extends a {
  private BroadcastReceiver c = new BroadcastReceiver(this) {
      public void onReceive(Context param1Context, Intent param1Intent) {
        Toast.makeText(param1Context, "myReceiver receive", 0).show();
        String str = param1Intent.getAction();
        if (param1Context.getPackageName().equals(str));
      }
    };
  
  protected void onCreate(Bundle paramBundle) {
    super.onCreate(paramBundle);
    setContentView(2130903041);
    Intent intent = getIntent();
    String str1 = intent.getStringExtra("ili");
    String str2 = intent.getStringExtra("lil");
    if (Encryto.doRawData(this, str1 + str2).equals("VEIzd/V2UPYNdn/bxH3Xig==")) {
      intent.setAction("android.test.action.MoniterInstallService");
      intent.setClass((Context)this, MoniterInstallService.class);
      intent.putExtra("company", "tencent");
      intent.putExtra("name", "hacker");
      intent.putExtra("age", 18);
      startActivity(intent);
      startService(intent);
    } 
    SharedPreferences.Editor editor = getSharedPreferences("test", 0).edit();
    editor.putString("ilil", str1);
    editor.putString("lili", str2);
    editor.commit();
  }
  
  public boolean onCreateOptionsMenu(Menu paramMenu) {
    getMenuInflater().inflate(2131099648, paramMenu);
    return true;
  }
  
  public boolean onOptionsItemSelected(MenuItem paramMenuItem) { return (paramMenuItem.getItemId() == 2131165188) ? true : super.onOptionsItemSelected(paramMenuItem); }
}

老规矩,查看onCreate方法:

protected void onCreate(Bundle paramBundle) {
    super.onCreate(paramBundle);
    setContentView(2130903041);
    Intent intent = getIntent();     //获取到传入的intent
    String str1 = intent.getStringExtra("ili");  //读取c
    String str2 = intent.getStringExtra("lil");  //读取d
//判断条件是c+d经过本地函数处理之后内容是否等于VEIzd/V2UPYNdn/bxH3Xig==
    if (Encryto.doRawData(this, str1 + str2).equals("VEIzd/V2UPYNdn/bxH3Xig==")) {
      intent.setAction("android.test.action.MoniterInstallService");
      intent.setClass((Context)this, MoniterInstallService.class);
      intent.putExtra("company", "tencent");
      intent.putExtra("name", "hacker");
      intent.putExtra("age", 18);
      startActivity(intent);
      startService(intent);
    } 
    SharedPreferences.Editor editor = getSharedPreferences("test", 0).edit();
    editor.putString("ilil", str1);
    editor.putString("lili", str2);
    editor.commit();
  }

这里有一个判断:判断条件是c+d经过本地函数处理之后内容是否等于VEIzd/V2UPYNdn/bxH3Xig==,如果判断结果为真则会开启一个新的activity: MoniterInstallService

我们先来研究这个判断条件内的函数,看看假如输入的c+d等于"VEIzd/V2UPYNdn/bxH3Xig=="会发生什么:

查看Encryto.doRawData(),发现是一个JNI方法。

上IDA,将so文件拖进IDA后找到j_doRawData之后无脑F5:

int __fastcall doRawData(int a1, int a2, int a3, int a4)
{
  int v4; // r4
  int v5; // r9
  int v6; // r6
  int v7; // r8
  int result; // r0
  int (__fastcall *v9)(int, char *, size_t); // r6
  char *v10; // r5
  size_t v11; // r2
  int v12; // [sp+0h] [bp-28h]
  int v13; // [sp+4h] [bp-24h]
  int v14; // [sp+8h] [bp-20h]
  int v15; // [sp+Ch] [bp-1Ch]
  char v16; // [sp+10h] [bp-18h]
  int v17; // [sp+18h] [bp-10h]

  v4 = a1;
  v5 = a4;
  if ( j_checkSignature(a1) != 1 )
    goto LABEL_7;
  v12 = *(_DWORD *)"thisisatestkey==";
  v13 = *(_DWORD *)"isatestkey==";
  v14 = *(_DWORD *)"estkey==";
  v15 = *(_DWORD *)"ey==";
  v16 = aThisisatestkey[16];
  v6 = (*(int (__fastcall **)(int, int, _DWORD))(*(_DWORD *)v4 + 676))(v4, v5, 0);
  v7 = j_AES_128_ECB_PKCS5Padding_Encrypt(v6, (int)&v12);
  (*(void (__fastcall **)(int, int, int))(*(_DWORD *)v4 + 680))(v4, v5, v6);
  result = (*(int (__fastcall **)(int, int))(*(_DWORD *)v4 + 668))(v4, v7);
  if ( _stack_chk_guard != v17 )
  {
LABEL_7:
    do
    {
      v9 = *(int (__fastcall **)(int, char *, size_t))(*(_DWORD *)v4 + 652);
      v10 = UNSIGNATURE[0];
      v11 = strlen(UNSIGNATURE[0]);
    }
    while ( _stack_chk_guard != v17 );
    result = v9(v4, v10, v11);
  }
  return result;
}

我们可以大胆的猜测(具体是为什么我也不知道),字符指针v6就是传入的字符串。

然后可以看到,输出是v7=j_AES_128_ECB_PKCS5Padding_Encrypt(v6, (int)&v12);

根据目测函数名,推测是128位的AES加密,模式是ECB,填充方式是PKCS5Padding。

然后我们观察到这个函数的v12是密钥,且前面有操作strcpy(v12,"thisisatestkey=="),因此可以知道密钥是v12.

然后打开在线解密网站:在线AES加解密

输入:

拿到明文为aimagetencent。

于是根据之前分析的,c+d拼接成aimagetencent。

不妨大胆假设c="aimage" ,d="tencent",输入一下试试看会发生什么。

我们在第一个输入:tencent

第二个输入框输入:aimage,

神奇的一幕出现了:

。。。。。。

开始我认为是我的模拟器版本只有4.4过低,于是用我的真机测试,依然闪退。

事情到此陷入了僵局。

分析一波判断结果为true之后发生的事情:

开启一个新的MoniterInstallService,点击进去这个MoniterInstallService看下代码:

package com.tencent.testvuln;

import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;

public class MoniterInstallService extends Service {
  private long a = 0L;
  
  private String b = null;
  
  private String c = null;
  
  private c d = null;
  
  private BroadcastReceiver e = new BroadcastReceiver(this) {
      public void onReceive(Context param1Context, Intent param1Intent) {
        this.a.b("");
        try {
          Thread.sleep(1000L);
        } catch (InterruptedException interruptedException) {
          interruptedException.printStackTrace();
        } 
        param1Intent = new Intent("android.setting.word");
        param1Intent.putExtra("1", MoniterInstallService.a(this.a));
        param1Intent.putExtra("2", MoniterInstallService.b(this.a));
        param1Context.sendBroadcast(param1Intent);
      }
    };
  
  private Handler f = new Handler(this) {
      public void handleMessage(Message param1Message) {
        switch (param1Message.what) {
          default:
            return;
          case 0:
            break;
        } 
        this.a.a("");
      }
    };
  
  void a(String paramString) {
    paramString = Environment.getExternalStorageDirectory().getPath() + "/crash/";
    if (this.d == null)
      this.d = new c(paramString); 
    this.d.startWatching();
  }
  
  void b(String paramString) {
    if (this.d != null)
      this.d.stopWatching(); 
  }
  
  public IBinder onBind(Intent paramIntent) { return null; }
  
  public void onCreate() {
    super.onCreate();
    IntentFilter intentFilter = new IntentFilter();
    intentFilter.addAction("com.tencent.testvul.service.MoniterFile");
    intentFilter.setPriority(2147483647);
    registerReceiver(this.e, intentFilter);
  }
  
  public void onDestroy() { super.onDestroy(); }
  
  public void onStart(Intent paramIntent, int paramInt) {
    super.onStart(paramIntent, paramInt);
    this.b = paramIntent.getStringExtra("ili");
    this.c = paramIntent.getStringExtra("lil");
    (new Thread(this) {
        public void run() {
          Message message = new Message();
          message.what = 0;
          MoniterInstallService.c(this.a).sendMessage(message);
        }
      }).start();
  }
}

大概扫了扫发现是一个广播开启和接收的Activity,和本次CTF关系应该不大,因此这个暂时不管它,继续往下分析SecondActivity的代码。

 SharedPreferences.Editor editor = getSharedPreferences("test", 0).edit();
    editor.putString("ilil", str1);
    editor.putString("lili", str2);
    editor.commit();

.............发现这代码它也没干啥事啊,就存储了一下输入的变量。

事情再次陷入了僵局。。。。。。。

然后发现在一个从未被使用过的类(之所以说它从未被使用过是因为如下:search搜索该类只找到它自己): FileDataActivity中发现了如下神秘代码:

package com.tencent.testvuln;

import android.os.Bundle;
import android.widget.TextView;
import com.tencent.testvuln.c.Encryto;

public class FileDataActivity extends a {
  private TextView c;
  
  protected void onCreate(Bundle paramBundle) {
    super.onCreate(paramBundle);
    setContentView(2130903042);
    this.c = (TextView)findViewById(2131165184);
    this.c.setText(Encryto.decode(this, "9YuQ2dk8CSaCe7DTAmaqAA=="));
  }
}

然后我们拿着串神秘代码去AES解密,就拿到了flag:

这题我不知道说什么好

-------end----------

发布了109 篇原创文章 · 获赞 34 · 访问量 12万+

猜你喜欢

转载自blog.csdn.net/shuaicenglou3032/article/details/104293686