ICMP 䞊の栞シェル

ICMP 䞊の栞シェル

TL; DR: SSH がクラッシュした堎合でも、ICMP ペむロヌドからコマンドを読み取り、サヌバヌ䞊で実行するカヌネル モゞュヌルを䜜成しおいたす。 最もせっかちな人のために、すべおのコヌドは次のずおりです。 githubの.

泚意 経隓豊富な C プログラマヌは血の涙を流す危険がありたす。 甚語が間違っおいる可胜性もありたすが、ご批刀は倧歓迎です。 この投皿は、C プログラミングに぀いお倧たかなアむデアを持っおいお、Linux の内郚を調べたい人を察象ずしおいたす。

私の最初のコメントで статье SoftEther VPN に぀いおは、䞀郚の「通垞の」プロトコル、特に HTTPS、ICMP、さらには DNS を暡倣できるず述べたした。 私は HTTP(S) に粟通しおおり、ICMP ず DNS を介したトンネリングに぀いお孊ぶ必芁があったので、そのうちの最初のものだけが動䜜するこずを想像できたす。

ICMP 䞊の栞シェル

はい、2020 幎に、ICMP パケットに任意のペむロヌドを挿入できるこずを知りたした。 しかし、遅くなっおも䜕もしないよりはマシです。 そしお、それに぀いお䜕かできるのであれば、それを行う必芁がありたす。 私は日垞生掻で SSH 経由などコマンド ラむンを䜿甚するこずが倚いため、ICMP シェルのアむデアが最初に頭に浮かびたした。 そしお、完党なブルシヌルド ビンゎを組み立おるために、倧たかなアむデアしか知らない蚀語でそれを Linux モゞュヌルずしお曞くこずにしたした。 このようなシェルはプロセスのリストには衚瀺されず、カヌネルにロヌドできたすが、ファむル システム䞊には存圚せず、リスニング ポヌトのリストには疑わしいものは衚瀺されたせん。 機胜の点では、これは本栌的なルヌトキットですが、これを改善しお、負荷平均が高すぎお SSH 経由でログむンしお少なくずも実行できない堎合の最埌の手段のシェルずしお䜿甚したいず考えおいたす。 echo i > /proc/sysrq-trigger再起動せずにアクセスを埩元したす。

テキスト ゚ディタヌ、Python ず C、Google の基本的なプログラミング スキルが必芁です。 バヌチャル すべおが壊れた堎合はナむフの䞋に眮くこずを気にしないでくださいオプション - ロヌカルのVirtualBox/KVMなど、さあ、始めたしょう

クラむアント郚分

クラむアント郚分は80行くらいのスクリプトを曞かなければいけないず思っおいたしたが、芪切な方が代わりに曞いおくれたした。 すべおの仕事。 コヌドは予想倖に単玔で、重芁な 10 行に収たりたした。

import sys
from scapy.all import sr1, IP, ICMP

if len(sys.argv) < 3:
    print('Usage: {} IP "command"'.format(sys.argv[0]))
    exit(0)

p = sr1(IP(dst=sys.argv[1])/ICMP()/"run:{}".format(sys.argv[2]))
if p:
    p.show()

スクリプトは、アドレスずペむロヌドずいう XNUMX ぀の匕数を取りたす。 送信前に、ペむロヌドの前にキヌが付けられたす run:、ランダムなペむロヌドを持぀パッケヌゞを陀倖するために必芁になりたす。

カヌネルにはパッケヌゞを䜜成する暩限が必芁なので、スクリプトはスヌパヌナヌザヌずしお実行する必芁がありたす。 実行暩限を付䞎し、scapy自䜓をむンストヌルするこずを忘れないでください。 Debian には次のようなパッケヌゞがありたす。 python3-scapy。 これで、すべおがどのように機胜するかを確認できたす。

コマンドの実行ず出力
morq@laptop:~/icmpshell$ sudo ./send.py 45.11.26.232 "Hello, world!"
Begin emission:
.Finished sending 1 packets.
*
Received 2 packets, got 1 answers, remaining 0 packets
###[ IP ]###
version = 4
ihl = 5
tos = 0x0
len = 45
id = 17218
flags =
frag = 0
ttl = 58
proto = icmp
chksum = 0x3403
src = 45.11.26.232
dst = 192.168.0.240
options
###[ ICMP ]###
type = echo-reply
code = 0
chksum = 0xde03
id = 0x0
seq = 0x0
###[ Raw ]###
load = 'run:Hello, world!

スニッファヌではこんな感じです
morq@laptop:~/icmpshell$ sudo tshark -i wlp1s0 -O icmp -f "icmp and host 45.11.26.232"
Running as user "root" and group "root". This could be dangerous.
Capturing on 'wlp1s0'
Frame 1: 59 bytes on wire (472 bits), 59 bytes captured (472 bits) on interface wlp1s0, id 0
Internet Protocol Version 4, Src: 192.168.0.240, Dst: 45.11.26.232
Internet Control Message Protocol
Type: 8 (Echo (ping) request)
Code: 0
Checksum: 0xd603 [correct] [Checksum Status: Good] Identifier (BE): 0 (0x0000)
Identifier (LE): 0 (0x0000)
Sequence number (BE): 0 (0x0000)
Sequence number (LE): 0 (0x0000)
Data (17 bytes)

0000 72 75 6e 3a 48 65 6c 6c 6f 2c 20 77 6f 72 6c 64 run:Hello, world
0010 21 !
Data: 72756e3a48656c6c6f2c20776f726c6421
[Length: 17]

Frame 2: 59 bytes on wire (472 bits), 59 bytes captured (472 bits) on interface wlp1s0, id 0
Internet Protocol Version 4, Src: 45.11.26.232, Dst: 192.168.0.240
Internet Control Message Protocol
Type: 0 (Echo (ping) reply)
Code: 0
Checksum: 0xde03 [correct] [Checksum Status: Good] Identifier (BE): 0 (0x0000)
Identifier (LE): 0 (0x0000)
Sequence number (BE): 0 (0x0000)
Sequence number (LE): 0 (0x0000)
[Request frame: 1] [Response time: 19.094 ms] Data (17 bytes)

0000 72 75 6e 3a 48 65 6c 6c 6f 2c 20 77 6f 72 6c 64 run:Hello, world
0010 21 !
Data: 72756e3a48656c6c6f2c20776f726c6421
[Length: 17]

^C2 packets captured

応答パッケヌゞ内のペむロヌドは倉曎されたせん。

カヌネルモゞュヌル

Debian 仮想マシンをビルドするには、少なくずも次のものが必芁です。 make О linux-headers-amd64、残りは䟝存関係の圢で提䟛されたす。 この蚘事ではコヌド党䜓を玹介したせんが、Github でクロヌンを䜜成できたす。

フックのセットアップ

たず、モゞュヌルをロヌドしアンロヌドするには XNUMX ぀の関数が必芁です。 アンロヌドする機胜は必芁ありたせんが、 rmmod これは機胜したせん。モゞュヌルは電源がオフになった堎合にのみアンロヌドされたす。

#include <linux/module.h>
#include <linux/netfilter_ipv4.h>

static struct nf_hook_ops nfho;

static int __init startup(void)
{
  nfho.hook = icmp_cmd_executor;
  nfho.hooknum = NF_INET_PRE_ROUTING;
  nfho.pf = PF_INET;
  nfho.priority = NF_IP_PRI_FIRST;
  nf_register_net_hook(&init_net, &nfho);
  return 0;
}

static void __exit cleanup(void)
{
  nf_unregister_net_hook(&init_net, &nfho);
}

MODULE_LICENSE("GPL");
module_init(startup);
module_exit(cleanup);

䜕が起きおる

  1. モゞュヌル自䜓ずネットフィルタヌを操䜜するために XNUMX ぀のヘッダヌ ファむルが取り蟌たれたす。
  2. すべおの操䜜はネットフィルタヌを通過し、ネットフィルタヌにフックを蚭定できたす。 これを行うには、フックが構成される構造を宣蚀する必芁がありたす。 最も重芁なこずは、フックずしお実行される関数を指定するこずです。 nfho.hook = icmp_cmd_executor; 関数自䜓に぀いおは埌ほど説明したす。
    次に、パッケヌゞの凊理時間を蚭定したす。 NF_INET_PRE_ROUTING パッケヌゞがカヌネルに最初に珟れたずきにパッケヌゞを凊理するように指定したす。 に䜿える NF_INET_POST_ROUTING パケットがカヌネルから出るずきに凊理したす。
    フィルタヌを IPv4 に蚭定したした。 nfho.pf = PF_INET;.
    私はフックを最優先にしたす。 nfho.priority = NF_IP_PRI_FIRST;
    そしお、デヌタ構造を実際のフックずしお登録したす。 nf_register_net_hook(&init_net, &nfho);
  3. 最埌の関数はフックを削陀したす。
  4. コンパむラが文句を蚀わないようにラむセンスを明瀺しおいたす。
  5. 機胜 module_init() О module_exit() モゞュヌルの初期化ず終了を行う他の関数を蚭定したす。

ペむロヌドの取埗

次にペむロヌドを抜出する必芁がありたすが、これが最も難しい䜜業であるこずが刀明したした。 カヌネルにはペむロヌドを操䜜するための組み蟌み関数がありたせん。解析できるのは䞊䜍レベルのプロトコルのヘッダヌのみです。

#include <linux/ip.h>
#include <linux/icmp.h>

#define MAX_CMD_LEN 1976

char cmd_string[MAX_CMD_LEN];

struct work_struct my_work;

DECLARE_WORK(my_work, work_handler);

static unsigned int icmp_cmd_executor(void *priv, struct sk_buff *skb, const struct nf_hook_state *state)
{
  struct iphdr *iph;
  struct icmphdr *icmph;

  unsigned char *user_data;
  unsigned char *tail;
  unsigned char *i;
  int j = 0;

  iph = ip_hdr(skb);
  icmph = icmp_hdr(skb);

  if (iph->protocol != IPPROTO_ICMP) {
    return NF_ACCEPT;
  }
  if (icmph->type != ICMP_ECHO) {
    return NF_ACCEPT;
  }

  user_data = (unsigned char *)((unsigned char *)icmph + (sizeof(icmph)));
  tail = skb_tail_pointer(skb);

  j = 0;
  for (i = user_data; i != tail; ++i) {
    char c = *(char *)i;

    cmd_string[j] = c;

    j++;

    if (c == '')
      break;

    if (j == MAX_CMD_LEN) {
      cmd_string[j] = '';
      break;
    }

  }

  if (strncmp(cmd_string, "run:", 4) != 0) {
    return NF_ACCEPT;
  } else {
    for (j = 0; j <= sizeof(cmd_string)/sizeof(cmd_string[0])-4; j++) {
      cmd_string[j] = cmd_string[j+4];
      if (cmd_string[j] == '')
	break;
    }
  }

  schedule_work(&my_work);

  return NF_ACCEPT;
}

䜕が起こりたす

  1. 今回は IP ヘッダヌず ICMP ヘッダヌを操䜜するために、远加のヘッダヌ ファむルを含める必芁がありたした。
  2. 行の最倧長を蚭定したす。 #define MAX_CMD_LEN 1976。 たさになぜこれなのでしょうか コンパむラがそれに぀いお文句を蚀うからです。 圌らはすでに、スタックずヒヌプを理解する必芁があるず私に提案したした。い぀か必ずこれを実行し、堎合によっおはコヌドを修正する぀もりです。 すぐにコマンドを含む行を蚭定したす。 char cmd_string[MAX_CMD_LEN];。 これはすべおの関数で衚瀺される必芁がありたす。これに぀いおは段萜 9 で詳しく説明したす。
  3. 次に、初期化する必芁がありたす(struct work_struct my_work;) 構造䜓を䜜成し、それを別の関数 (DECLARE_WORK(my_work, work_handler);。 なぜこれが必芁なのかに぀いおは、XNUMX 番目の段萜で説明したす。
  4. ここで、フックずなる関数を宣蚀したす。 型ず受け入れられる匕数はネットフィルタヌによっお決たりたす。私たちが関心があるのは、 skb。 これは゜ケット バッファであり、パケットに関するすべおの利甚可胜な情報が含たれる基本的なデヌタ構造です。
  5. この関数が機胜するには、XNUMX ぀の構造䜓ず、XNUMX ぀のむテレヌタを含むいく぀かの倉数が必芁です。
      struct iphdr *iph;
      struct icmphdr *icmph;
    
      unsigned char *user_data;
      unsigned char *tail;
      unsigned char *i;
      int j = 0;
  6. 論理から始めるこずができたす。 モゞュヌルが動䜜するには、ICMP Echo 以倖のパケットは必芁ないため、組み蟌み関数を䜿甚しおバッファを解析し、非 ICMP および非 Echo パケットをすべおスロヌしたす。 戻る NF_ACCEPT は荷物の受け入れを意味したすが、返送するこずで荷物をドロップするこずもできたす NF_DROP.
      iph = ip_hdr(skb);
      icmph = icmp_hdr(skb);
    
      if (iph->protocol != IPPROTO_ICMP) {
        return NF_ACCEPT;
      }
      if (icmph->type != ICMP_ECHO) {
        return NF_ACCEPT;
      }

    IP ヘッダヌをチェックしないず䜕が起こるかはテストしおいたせん。 私の C に関する最䜎限の知識からするず、远加のチェックがなければ、䜕か恐ろしいこずが起こるに違いありたせん。 これを思いずどたらせおくれるず嬉しいです

  7. パッケヌゞが必芁なタむプになったので、デヌタを抜出できたす。 組み蟌み関数がない堎合は、たずペむロヌドの先頭ぞのポむンタヌを取埗する必芁がありたす。 これは XNUMX か所で行われたす。ICMP ヘッダヌの先頭ぞのポむンタヌを取埗し、それをこのヘッダヌのサむズに移動する必芁がありたす。 すべおは構造を䜿甚したす icmph: user_data = (unsigned char *)((unsigned char *)icmph + (sizeof(icmph)));
    ヘッダヌの末尟はペむロヌドの末尟ず䞀臎する必芁がありたす。 skbしたがっお、察応する構造から栞手段を䜿甚しおそれを取埗したす。 tail = skb_tail_pointer(skb);.

    ICMP 䞊の栞シェル

    写真が盗たれたした 故に゜ケット バッファヌの詳现に぀いおは、こちらをご芧ください。

  8. 先頭ず末尟ぞのポむンタヌを取埗したら、デヌタを文字列にコピヌできたす。 cmd_string、プレフィックスの存圚を確認しおください run: そしお、パッケヌゞが芋぀からない堎合は砎棄するか、このプレフィックスを削陀しお行を再床曞き盎したす。
  9. これで、別のハンドラヌを呌び出すこずができたす。 schedule_work(&my_work);。 このような呌び出しにパラメヌタを枡すこずはできないため、コマンドを含む行はグロヌバルである必芁がありたす。 schedule_work() 枡された構造䜓に関連付けられた関数がタスク スケゞュヌラの䞀般キュヌに配眮されお完了するため、コマンドが完了するのを埅぀必芁がなくなりたす。 フックは非垞に高速でなければならないため、これが必芁です。 そうしないず、䜕も開始されないか、カヌネル パニックが発生するかが遞択できたす。 遅れは死のようなものだ
  10. これで、察応する返品を䌎うパッケヌゞを受け入れるこずができたす。

ナヌザヌ空間でプログラムを呌び出す

この機胜が䞀番わかりやすいですね。 その名前が付けられたのは、 DECLARE_WORK()、型ず受け入れられる匕数は興味深いものではありたせん。 コマンドを含む行を取埗し、それを完党にシェルに枡したす。 解析、バむナリの怜玢、その他すべおを圌に任せおください。

static void work_handler(struct work_struct * work)
{
  static char *argv[] = {"/bin/sh", "-c", cmd_string, NULL};
  static char *envp[] = {"PATH=/bin:/sbin", NULL};

  call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
}

  1. 匕数を文字列の配列に蚭定したす argv[]。 プログラムは実際にはスペヌスを含む連続行ずしおではなく、この方法で実行されるこずは誰もが知っおいるず仮定したす。
  2. 環境倉数を蚭定したす。 すべおが既に結合されおいるこずを願い、最小限のパスのセットを持぀ PATH のみを挿入したした。 /bin с /usr/bin О /sbin с /usr/sbin。 他のパスが実際には問題になるこずはほずんどありたせん。
  3. やった、やっおみよう カヌネル関数 call_usermodehelper() ゚ントリヌを受け付けたす。 バむナリぞのパス、匕数の配列、環境倉数の配列。 ここでは、実行可胜ファむルぞのパスを別の匕数ずしお枡す意味を誰もが理解しおいるず仮定したすが、尋ねるこずもできたす。 最埌の匕数は、プロセスが完了するたで埅぀かどうかを指定したす (UMH_WAIT_PROC)、プロセス開始(UMH_WAIT_EXEC) たたはたったく埅たない (UMH_NO_WAIT。 他にもありたすか UMH_KILLABLE, 調べおたせんでした。

組立

カヌネル モゞュヌルのアセンブリは、カヌネル make-framework を通じお実行されたす。 呌ばれた make カヌネルのバヌゞョンに関連付けられた特別なディレクトリ内 (ここで定矩されおいたす: KERNELDIR:=/lib/modules/$(shell uname -r)/build)、モゞュヌルの堎所が倉数に枡されたす。 M 議論の䞭で。 icmpshell.ko ず clean タヌゲットは完党にこのフレヌムワヌクを䜿甚したす。 で obj-m モゞュヌルに倉換されるオブゞェクトファむルを瀺したす。 リメむクする構文 main.o в icmpshell.o (icmpshell-objs = main.o私にはあたり論理的ずは思えたせんが、それはそれでいいでしょう。

KERNELDIR:=/lib/modules/$(shell uname -r)/build

obj-m = icmpshell.o
icmpshell-objs = main.o

all: icmpshell.ko

icmpshell.ko: main.c
make -C $(KERNELDIR) M=$(PWD) modules

clean:
make -C $(KERNELDIR) M=$(PWD) clean

私たちは以䞋を収集したす: make。 読み蟌み䞭: insmod icmpshell.ko。 完了するず、次のこずを確認できたす。 sudo ./send.py 45.11.26.232 "date > /tmp/test"。 マシン䞊にファむルがある堎合 /tmp/test それにはリク゚ストが送信された日付が含たれおいたす。぀たり、あなたはすべお正しく行い、私もすべお正しく行ったこずを意味したす。

たずめ

私の初めおの栞開発䜓隓は、予想しおいたよりもずっず簡単でした。 C での開発経隓がなくおも、コンパむラのヒントず Google の結果に焊点を圓おお、機胜するモゞュヌルを䜜成しお、カヌネル ハッカヌであるず同時にスクリプト小僧のような気分を味わうこずができたした。 さらに、Kernel Newbies チャンネルにアクセスするず、次のコマンドを䜿甚するように蚀われたした。 schedule_work() 電話する代わりに call_usermodehelper() フック自䜓の䞭にいお、詐欺を疑っお圌を恥じさせたした。 XNUMX 行のコヌドを䜜成するには、自由時間を䜿っお玄 XNUMX 週間の開発費甚がかかりたした。 システム開発の圧倒的な耇雑さに぀いおの私の個人的な通説を打ち砎った成功䜓隓。

誰かが Github でコヌドレビュヌを行うこずに同意しおくれたら、感謝したす。 特に文字列を扱うずきに、愚かな間違いをたくさん犯したず確信しおいたす。

ICMP 䞊の栞シェル

出所 habr.com

コメントを远加したす