株式会社Ninjastars 技術研究部

「もっと楽しく安全なゲームの世界を創る」

Android LD_PRELOAD攻撃とその対策

株式会社Ninjastarsセキュリティエンジニアの一瀬です。
今日はAndroidアプリケーションでのLD_PRELOAD攻撃とその対策について書かせていただきます。
チート行為などにおいてはLD_PRELOADを利用した攻撃は一般的ではありませんが、存在を知らないとリスク対策もできないのでご紹介いたします。

前提
Android Studioセットアップ済み
ndk-buildができる状態

環境
rootedな実機 or Android Emulator

今回やること
LD_PRELOADで動的ライブラリ関数を上書きする | Siguniang's Blog

まず上記の方の実験用プログラムをAndroidで動かすことを目標とします。
また今回はその対策手法についてもご説明させていただきます。

セットアップ手順
適当に作成したフォルダにjniフォルダを作り下記のAndroid.mk、Application.mk、random_num.c、unrandom.c、myrandom.cを作成してください。
AndroidStudioのTerminalで

cd 作成したフォルダ
ndk-build

でビルドが出来ます。
libsフォルダにx86、armeabi-v7aのバイナリがそれぞれできますので環境に合わせてコマンドプロンプトから

adb push  (x86 or armバイナリのrandom_numのパス) /data/local/tmp
adb push  (x86 or armバイナリのlibunrandomのパス) /data/local/tmp
adb push  (x86 or armバイナリのlibmyrandomのパス) /data/local/tmp
adb shell
cd data/local/tmp
chmod 755 random_num

AndroidにおけるLD_PRELOADの設定
1.端末上でSELinuxを無効化。
2a.アプリケーションの場合:
setpropでアプリのパッケージに対して LD_PRELOADを設定する。この時パッケージ名にwrap.を付加する。
例えば対象アプリのパッケージ名が"com.doraneko.SurvivalShooter"、読み込ませたいsoファイルのパスが/data/local/tmp/libinject.soの場合

setprop wrap.com.doraneko.SurvivalShooter LD_PRELOAD=/data/local/tmp/libinject.so

2b.実行ファイルの場合:
例えば実行ファイル名がhello、読み込ませたいsoファイルのパスがdata/local/tmp/libinject.soの場合

LD_PRELOAD=./data/local/tmp/libinject.so ./hello

実験
それでは実際にrandom_numに対してlibunrandom.so、libmyrandom.soをLD_PRELOADを用いてインジェクションしてみます。

LD_PRELOAD=./data/local/tmp/libunrandom.so ./random_num
LD_PRELOAD=./data/local/tmp/libmyrandom.so ./random_num


f:id:Ninjastars:20190212145103p:plain
実行結果

f:id:Ninjastars:20190213180418p:plain
インジェクションされたsoファイル

見事にrandom関数がインジェクションしたsoファイルの関数に置換されています。また画像のようにsoファイルがインジェクションされていることが分かります。
このように既存の関数を置換される危険性があるとともに、soファイルのインジェクション自体がその他の攻撃の起点にもなりうる可能性があります。

一般的なチート手法ではGameGuardianやgdb、Fridaなどを用いてptraceでの対象プロセスへのアタッチが必要となります。
しかしLD_PRELOAD攻撃の場合ptraceでのアタッチを伴わずsoファイルのインジェクションや関数の置換が可能となります。
常にこうした攻撃手法が存在するということを念頭に置いて、防御面も考えていく必要があるかと思われます。

ソースコード
※AndroidStudioでndkビルドするとソースコード上でrand関数で記述してもlrand48関数でコンパイルされるようなので、unrandom.c、myrandom.cでは置換すべき関数としてlrand48で記述しています。

Android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_CFLAGS += -fPIE
LOCAL_LDFLAGS += -fPIE -pie 
LOCAL_MODULE    := random_num
LOCAL_SRC_FILES := random_num.c
include $(BUILD_EXECUTABLE)

############################################
include $(CLEAR_VARS)

LOCAL_MODULE_FILENAME:= libunrandom
LOCAL_MODULE    := unrandom
LOCAL_SRC_FILES := unrandom.c

include $(BUILD_SHARED_LIBRARY)
############################################
include $(CLEAR_VARS)
LOCAL_MODULE_FILENAME:= libmyrandom
LOCAL_MODULE    := myrandom
LOCAL_SRC_FILES := myrandom.c

include $(BUILD_SHARED_LIBRARY)

Application.mk

APP_ABI := x86 armeabi-v7a

random_num.c

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
 
int main(){
  srand(time(NULL));
  int i = 10;
  while(i--) printf("%d\n",rand());
  return 0;
}

unrandom.c

int lrand48(){
    return 42; //the most random number in the universe
}

myrandom.c

#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
 
typedef int (*orig_rand_f_type)();
 
int lrand48(){
  printf("custom rand is called\n");
  orig_rand_f_type orig_rand;
  orig_rand = (orig_rand_f_type)dlsym(RTLD_NEXT, "lrand48");
  return orig_rand();
}

防御手法
通常の方法でアプリケーションを実行した場合、親プロセスはzygoteになります。

USER      PID   PPID  VSIZE  RSS   WCHAN            PC  NAME
root      1841  1     1611188 125080          0 b7700c60 S zygote
......
u0_a48    4267  1841  1112668 145184          0 b7700c60 S com.doraneko.SurvivalShooter

しかしLD_PRELOADを設定した状態でアプリを起動すると親はzygoteでなくなります。(実際は/system/bin/sh)

USER      PID   PPID  VSIZE  RSS   WCHAN            PC  NAME
root      1841  1     1611188 125080          0 b7700c60 S zygote
........
u0_a48    4569  4557  1125376 189684          0 b7720c60 S com.doraneko.SurvivalShooter

つまり対策の一つの手法としては親プロセスがzygoteであるか確認する方法が有効です。
ただここで注意しなくてはいけないのは、チェック処理で標準関数を使用するとそれ自体攻撃者によって置換されてしまう可能性があるということです。
実際上は攻撃手法に対する対策だけでなく、その対策の回避方法に対する更なる対策など何重にも防御していく必要があります。

最後に対象アプリケーションの送受信関数をLD_PRELOADで置換して、HTTP通信の内容をlogcatで出力するプログラムを作成しました。

LD_PRELOADによるHTTP通信キャプチャ

注意事項
本レポートに記載されている内容を許可されていないソフトウェアで行うと、場合によっては犯罪行為となる可能性があります。そのため、記事の内容を試す際には許可されたソフトウェアに対してのみ実施するようにしてください。

本レポートについて
お問い合せ
E-mail:ichise@ninjastars-net.com

株式会社Ninjastarsエンジニア
一瀬健二郎