m0nst3r's blog

Hello, Bugs

0%

网址:https://overthewire.org/wargames/bandit/

目前就34个关卡,大部分比较容易,有几个需要一些搜索.

不写整体的writeup了,只写其中做的几个笔记

find

find / -type f -user xxx -group yyy -size 33c ! -executable 2>/dev/null -exec cat {} \;

cut/awk

cat data.txt | grep millionth | cut -f 2

cat data.txt | grep millionth | awk '{print $2}'

sort

cat data.txt | sort | uniq -c | sort -nr | tail -n 1 | awk '{print $2}'

Read more »

操作

在Burp中导出证书,这里的名字为burp.der.

然后在命令行中进行如下操作:

1
2
3
4
5
6
7
openssl x509 -inform DER -in burp.der -out burp.pem #转换格式
openssl x509 -inform PEM -subject_hash_old -in burp.pem | head -1 #打印hash,并将pem命名为hash.0
> 9a5ba575
cp burp.pem 9a5ba575.0
adb remount #重新mount
adb push 9a5ba575.0 /system/etc/security/cacerts/ #传上去
adb reboot #搞定

前提

  1. 手机完全root

适用

要测试的APP在容器是的容器里面,sslunpinning有时不能将所有层都hook好,导致一部分流量仍然提示证书错误.

可能遇到的问题

1
2
remount of /system failed: Read-only file system
remount failed
Read more »

初次体验基于栈溢出的PWN!

源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/*
* phoenix/stack-five, by https://exploit.education
*
* Can you execve("/bin/sh", ...) ?
*
* What is green and goes to summer camp? A brussel scout.
*/

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

#define BANNER \
"Welcome to " LEVELNAME ", brought to you by https://exploit.education"

char *gets(char *);

void start_level() {
char buffer[128];
gets(buffer);
}

int main(int argc, char **argv) {
printf("%s\n", BANNER);
start_level();
}

分析

stack-four基本一样,只不过buffer大了一些。
过这个关卡,不是要执行到complete_level函数了,而是要get shell。也就是通过溢出漏洞,来执行我们自己的程序,即shellcode

shellcode就是一段执行返回一个shell的汇编代码。

我们将shellcode写到栈中,再通过溢出控制RIP,让程序去执行我们在栈中写好的shellcode,从而拿到shell

所以,在栈中基本上是这样的:

image-20190411231630801.png
upload successful

为了让我们的shellcode顺利执行,nopsled最好要有,因为有比如环境变量等的影响,栈中的地址会出现小幅度的偏移。

Read more »

这个关卡是一个标准的栈溢出的例子。

源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
/*
* phoenix/stack-four, by https://exploit.education
*
* The aim is to execute the function complete_level by modifying the
* saved return address, and pointing it to the complete_level() function.
*
* Why were the apple and orange all alone? Because the bananna split.
*/

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

#define BANNER \
"Welcome to " LEVELNAME ", brought to you by https://exploit.education"

char *gets(char *);

void complete_level() {
printf("Congratulations, you've finished " LEVELNAME " :-) Well done!\n");
exit(0);
}

void start_level() {
char buffer[64];
void *ret;

gets(buffer);

ret = __builtin_return_address(0);
printf("and will be returning to %p\n", ret);
}

int main(int argc, char **argv) {
printf("%s\n", BANNER);
start_level();
}

分析

main调用start_levelstart_level中有一个gets函数会千万栈溢出,利用溢出漏洞我们可以控制RIP/EIP,也就是程序执行流程。通过将返回地址覆盖成complete_level函数的地址,就过关了。

实操

先来看一下主要函数部分的汇编代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
000000000040061d <complete_level>:
40061d: 55 push %rbp
40061e: 48 89 e5 mov %rsp,%rbp
400621: bf f0 06 40 00 mov $0x4006f0,%edi
400626: e8 55 fe ff ff callq 400480 <puts@plt>
40062b: bf 00 00 00 00 mov $0x0,%edi
400630: e8 5b fe ff ff callq 400490 <exit@plt>

0000000000400635 <start_level>:
400635: 55 push %rbp
400636: 48 89 e5 mov %rsp,%rbp
400639: 48 83 ec 50 sub $0x50,%rsp
40063d: 48 8d 45 b0 lea -0x50(%rbp),%rax
400641: 48 89 c7 mov %rax,%rdi
400644: e8 27 fe ff ff callq 400470 <gets@plt>
400649: 48 8b 45 08 mov 0x8(%rbp),%rax
40064d: 48 89 45 f8 mov %rax,-0x8(%rbp)
400651: 48 8b 45 f8 mov -0x8(%rbp),%rax
400655: 48 89 c6 mov %rax,%rsi
400658: bf 33 07 40 00 mov $0x400733,%edi
40065d: b8 00 00 00 00 mov $0x0,%eax
400662: e8 f9 fd ff ff callq 400460 <printf@plt>
400667: 90 nop
400668: c9 leaveq
400669: c3 retq

000000000040066a <main>:
40066a: 55 push %rbp
40066b: 48 89 e5 mov %rsp,%rbp
40066e: 48 83 ec 10 sub $0x10,%rsp
400672: 89 7d fc mov %edi,-0x4(%rbp)
400675: 48 89 75 f0 mov %rsi,-0x10(%rbp)
400679: bf 50 07 40 00 mov $0x400750,%edi
40067e: e8 fd fd ff ff callq 400480 <puts@plt>
400683: b8 00 00 00 00 mov $0x0,%eax
400688: e8 a8 ff ff ff callq 400635 <start_level>
40068d: b8 00 00 00 00 mov $0x0,%eax
400692: c9 leaveq
400693: c3 retq
400694: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
40069b: 00 00 00
40069e: 66 90 xchg %ax,%ax

call汇编指令分为两个部分,

  1. 将当前指令的下一条指令地址压入栈中
  2. JMP(无条件跳转)到目标函数地址。
Read more »

stack-two基本上于stack-one一样,只不过需要设置一个环境变量,程序是从环境变量中获取的值。

源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/*
* phoenix/stack-three, by https://exploit.education
*
* The aim is to change the contents of the changeme variable to 0x0d0a090a
*
* When does a joke become a dad joke?
* When it becomes apparent.
* When it's fully groan up.
*
*/

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

#define BANNER \
"Welcome to " LEVELNAME ", brought to you by https://exploit.education"

char *gets(char *);

void complete_level() {
printf("Congratulations, you've finished " LEVELNAME " :-) Well done!\n");
exit(0);
}

int main(int argc, char **argv) {
struct {
char buffer[64];
volatile int (*fp)();
} locals;

printf("%s\n", BANNER);

locals.fp = NULL;
gets(locals.buffer);

if (locals.fp) {
printf("calling function pointer @ %p\n", locals.fp);
fflush(stdout);
locals.fp();
} else {
printf("function pointer remains unmodified :~( better luck next time!\n");
}

exit(0);
}

分析

main函数中并没有调用complete_level函数的地方,要完成这个关卡,需要想办法调用这个函数。
main函数中,可通过溢出gets函数,覆盖local.fp指针,将fp的值改变为complate_level函数的地址,就完成了。

实操

先查看一下二进制文件的信息:

1
2
3
4
5
6
7
8
9
user@phoenix-amd64:/opt/phoenix/amd64$ checksec ./stack-three 
[*] '/opt/phoenix/amd64/stack-three'
Arch: amd64-64-little
RELRO: No RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x400000)
RWX: Has RWX segments
RPATH: '/opt/phoenix/x86_64-linux-musl/lib'

我们发现No RELRO,也就是没有地址重定位。
通过ldd命令也可以查看是否开启了地址重定位:

1
2
3
4
5
6
7
8
9
user@phoenix-amd64:/opt/phoenix/amd64$ ldd stack-three 
linux-vdso.so.1 (0x00007ffff7ffa000)
libc.so => /opt/phoenix/x86_64-linux-musl/lib/libc.so (0x00007ffff7b45000)
user@phoenix-amd64:/opt/phoenix/amd64$ ldd stack-three
linux-vdso.so.1 (0x00007ffff7ffa000)
libc.so => /opt/phoenix/x86_64-linux-musl/lib/libc.so (0x00007ffff7b45000)
user@phoenix-amd64:/opt/phoenix/amd64$ ldd stack-three
linux-vdso.so.1 (0x00007ffff7ffa000)
libc.so => /opt/phoenix/x86_64-linux-musl/lib/libc.so (0x00007ffff7b45000)
Read more »

源代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/*
* phoenix/stack-one, by https://exploit.education
*
* The aim is to change the contents of the changeme variable to 0x496c5962
*
* Did you hear about the kid napping at the local school?
* It's okay, they woke up.
*
*/

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

#define BANNER \
"Welcome to " LEVELNAME ", brought to you by https://exploit.education"

int main(int argc, char **argv) {
struct {
char buffer[64];
volatile int changeme;
} locals;

printf("%s\n", BANNER);

if (argc < 2) {
errx(1, "specify an argument, to be copied into the \"buffer\"");
}

locals.changeme = 0;
strcpy(locals.buffer, argv[1]);

if (locals.changeme == 0x496c5962) {
puts("Well done, you have successfully set changeme to the correct value");
} else {
printf("Getting closer! changeme is currently 0x%08x, we want 0x496c5962\n",
locals.changeme);
}

exit(0);
}

分析

危险的strcpy()。结构体中的changeme变量会在进行strcpy时被溢出覆盖。记得stack-zero的目的,是改变changeme的值就会通过,但这个关卡要求我们必须将changeme改变成0x496c5962才行。
结构体locals包含两个成员,与stack-zero相同。64个字符+1个int。

实操

首先,strcpy是从argv[1]中获取的输入,所以如果我们直接将输出传给stack-one,会出错:

1
2
3
4
5
6
7
8
user@phoenix-amd64:~$ python -c "print 'A'*65"
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
user@phoenix-amd64:~$ python -c "print 'A'*65" | /opt/phoenix/amd64/stack-one
Welcome to phoenix/stack-one, brought to you by https://exploit.education
stack-one: specify an argument, to be copied into the "buffer"
close failed in file object destructor:
sys.excepthook is missing
lost sys.stderr

解决办法是用xargs命令:

1
2
3
user@phoenix-amd64:~$ python -c "print 'A'*65" | xargs /opt/phoenix/amd64/stack-one 
Welcome to phoenix/stack-one, brought to you by https://exploit.education
Getting closer! changeme is currently 0x00000041, we want 0x496c5962

可以看到,我们将changeme改变为了0x41,即字符A
接下来就简单了,只要构造0x496c5962就可以。
使用pwntoolsp32/p64即可。

Read more »

exploit.education/stack-zero

作为一个逆向、pwn的新手新新手,找个练习的平台还是不错的。最近在看 liveOverFlow的Youtube视频,发现了这个东西,感觉不错,跟着做一做,希望能够有所提升。

环境

  1. https://exploit.education网站下载Phoenix 虚拟镜像
  2. 安装qemu
  3. 解压镜像文件,执行其中的boot-exploit-education-phoenix-amd64.sh
  4. 连接虚拟机:
    1
    ssh user@127.0.0.1 -p 2222

步骤

首先更新系统,更新gdb gef, 参考https://github.com/hugsy/gef

/opt/phoenix/amd64下面就是我们要解决的binary了,在exploit.education上面还有源码 ,来看下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/*
* phoenix/stack-zero, by https://exploit.education
*
* The aim is to change the contents of the changeme variable.
*
* Scientists have recently discovered a previously unknown species of
* kangaroos, approximately in the middle of Western Australia. These
* kangaroos are remarkable, as their insanely powerful hind legs give them
* the ability to jump higher than a one story house (which is approximately
* 15 feet, or 4.5 metres), simply because houses can't can't jump.
*/

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

#define BANNER \
"Welcome to " LEVELNAME ", brought to you by https://exploit.education"

char *gets(char *);

int main(int argc, char **argv) {
struct {
char buffer[64];
volatile int changeme;
} locals;

printf("%s\n", BANNER);

locals.changeme = 0;
gets(locals.buffer);

if (locals.changeme != 0) {
puts("Well done, the 'changeme' variable has been changed!");
} else {
puts(
"Uh oh, 'changeme' has not yet been changed. Would you like to try "
"again?");
}

exit(0);
}

locals结构体有两个成员,一个是64字节大小的char类型的buffer变量,一个是4字节大小的volatile int类型的changeme变量。

程序首先会输出一句话,然后将locals结构体中的changeme成员赋值为0,然后通过使用gets函数获取用户输入,将内容写入locals结构体中的buffer中去。

Read more »

目的

分析一下Cknife的源码,学习Java,顺便修改Cknife,为其添加异或的加密方式,看看能不能绕过一些waf。

src/com/ms509/ui/Cknife.java

入口点

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Cknife {
public static void main(String[] args) {
// TODO Auto-generated method stub
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
new InitConfig(); //配置初始化
setLookFeel(); //外观
new MainFrame(); //主窗口

}
});
}

EventQueueimport java.awt.EventQueue;这个导入进来的。

InitConfig

三个方法:

  • Init()
  • WriteParams()
  • LoadParams()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
private void Init() {
File conf = new File("Config.ini");
if (conf.exists()) {
// WriteParams(); //调试的时候取消注释,即无论怎么都要重新写一遍配置文件,发布的时候不要忘记注释掉。
LoadParams();
} else {
WriteParams();
LoadParams();

}
}

private void WriteParams() {
Configuration config = new Configuration();
config.setValue("SPL", "->|");
config.setValue("SPR", "|<-");
config.setValue("CODE", "code");
config.setValue("ACTION", "action");
config.setValue("PARAM1", "z1");
....
}

private void LoadParams() {
Configuration config = new Configuration();
Safe.SPL = config.getValue("SPL");
Safe.SPR = config.getValue("SPR");
Safe.CODE = config.getValue("CODE");
....
}
Read more »

要hook的目标

这是个frida教程的一个简单的apk.

URL: https://11x256.github.io/Frida-hooking-android-part-1/

Apk的源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package com.example.a11x256.frida_test;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.util.Base64;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Random;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

public class my_activity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_activity);
while (true){

try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}

fun(50,30);
}
}

void fun(int x , int y ){
Log.d("Sum" , String.valueOf(x+y));
}


}

我们要Hook fun这个方法。

新建类

upload successful

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.example.michael.xposed_1;

import de.robv.android.xposed.IXposedHookLoadPackage;
import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam;
import android.util.Log;

public class test implements IXposedHookLoadPackage {
@Override
public void handleLoadPackage(LoadPackageParam lpparam) throws Throwable{
if (lpparam.packageName.equals("com.example.a11x256.frida_test")) {
findAndHookMethod("com.example.a11x256.frida_test.my_activity", lpparam.classLoader,"fun", int.class, int.class, new XC_MethodHook(){
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
Log.e("Xposed", "Xposed Hooked");
}
});
}
}
}

配置xposed

Read more »

新建空的android项目,没有Activity

目录结构如下:

upload successful

修改build.gradle文件

upload successful

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
apply plugin: 'com.android.application'

android {
compileSdkVersion 28
defaultConfig {
applicationId "com.example.michael.xposed_1"
minSdkVersion 15
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}

# 下面这三行是新加的
repositories {
jcenter();
}

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:28.0.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
# 下面这两行是新加的
compileOnly 'de.robv.android.xposed:api:82'
compileOnly 'de.robv.android.xposed:api:82:sources'
}

修改AndroidManifest.xml

upload successful

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.michael.xposed_1">

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme" > <!--以前这里是application的闭合,要修改一下,在meta-data之后再闭合application-->

<!--增加三个meta-data-->
<meta-data
android:name="xposedmodule"
android:value="true" />

<meta-data
android:name="xposedminversion"
android:value="82" />

<meta-data
android:name="xposeddescription"
android:value="Xposed Hook Demo 1" />
</application> <!--闭合application-->
</manifest>

Build APK

Read more »