Linux Gazette 2004年7月投稿記事
目次
07/05/2004 - 11:05 Getting Comcast Email on Home Linux Box by Mike Chirico
07/10/2004 - 08:48 An introduction to Softirqs, Bottom halves and Tasklets by Nikhil Barghava
07/13/2004 - 12:21 Writing Arbitrary Executable Code for x86 Linux Systems by Victor Castro
07/15/2004 - 20:24 Spinlocks as locking construct in SMP systems by Nikhil Bhargava
07/21/2004 - 00:37 Little "Live" Linuxes - The Coolest Things Since Sliced Bread by Crouse
07/21/2004 - 16:27 Automating FTP, Generating Email Alerts, Sending GPG Encrypted Email from Command Prompt by Mike Chirico
家庭用LinuxボックスでComcast E-メールを入手
投稿者:mchirico 、07/05/2004 - 11:05. 記事|ハウツー
別題:出信メールの引渡しと、ユーザ名及びホスト名の仮装
以下では、Comcastケーブルモデモを経由してインターネットに接続する家庭用Linuxボックスを用いるComcast e-メール送受信法を説明する。面白くするため、Comcast e-メールはLinux コンピュータのアカウントとは異なると仮定する。それでも、"mutt", "elm" 又は何かを通じて、他のComcastユーザ又はインターネット上の誰かにe−メールを送ることが出来る。またe-メールを受け取ったら、ローカルLinuxアカウントに送ることが出来る。
これらは、Comcastアカウントが "mchirico -at- comcast.net" で、Linux ローカルアカウントが"chirico - at - third-fl-71" であるとして、書いてある。ローカルアカウントでは "mchirico" の "m" を省略しているのに注意。
これらは別の "ISP" を用いるときにも同様に役立つ。
ステップ 1:
ホームディレクトリの中に ".fetchmailrc" を作る。私の場合は、
/home/chirico
であった。
ここでも、comcastは "mchirico" で、Linux アカウントは "chirico" である。
また、"keep" オプションが規定されているので、ここでe-メールはサーバに保持される。 "keep" を外すとComcastアカウントが一杯になるを防ぐ。
以下は、e-メールをssl経由で受け取る。自分のパスワードを入れること。下に示すパスワードを残してはいけない。
#
#
# Comcast用サンプル.fetchmailrc ファイル
#
# 90秒毎にメールをチェック
set daemon 90
set syslog
set postmaster chirico
# bouncemail を設定
#
# Comcast e-メールはmchirico だが、コンピュータはproto POP3を用いる
chirico poll mail.comcast.net でオプションはdnsでない
user 'mchirico' with pass "secretpassword" is 'chirico' here
options ssl sslcertck sslcertpath '/usr/share/ssl/certs' keep
smtphost comcast.net
# end .fetchmailrc
上の行の若干は隠されている。完全な ".fetchmailrc"は以下からダウンロード出来る:
fetchmail をスタートするには次のコマンドを出す:
$ fetchmail
ステップ 2:
この記事を書いたときは、8.13.0が最新バージョンで、以下からダウンロードした:
configure, make make installの代わりに "./Build -c" と "./Build Install" を用いる
コンパイルオプションが "devtools/Site/site.config.m4"に規定されている。
以下は、Redhat 9上でコンフィギュアした"SASL" と "STARTTLS"のある "site.config.m4"ファイルの例である。Redhat 9 "openssl"は、下に示すように、別のディレクトリにある "kerberos" ファイルに頼っていることに注意。
APPENDDEF(`conf_sendmail_ENVDEF',`-DSTARTTLS')
APPENDDEF(`conf_sendmail_LIBS',`-lssl -lcrypto ')
APPENDDEF(`conf_sendmail_ENVDEF',`-DSASL')
APPENDDEF(`conf_sendmail_LIBS',`-lsasl')
APPENDDEF(`confINCDIRS',`-I/usr/kerberos/include')
APPENDDEF(`confINCDIRS',`-I/usr/include/openssl/include')
APPENDDEF(`confLIBDIRS',`-L/usr/kerberos/lib -L/usr/include/openssl/lib')
完全な "site.config.m4" は次の場所にある:
コンフィギュレーション・ファイルがあれば、バックアップしておくのがよい:
$ cp /etc/mail/sendmail.mc /etc/mail/OLDsendmail.mc
$ cp /etc/mail/sendmail.cf /etc/mail/OLDsendmail.cf
次にsendmail ディレクトリから "Build" して "Install"する
$ ./Build -c
$ ./Build install
不必要だが、"private CA (認証権限)" を設けることが出来る。
以下のステップは不要だが、簡単なのでここに含む。
$ cd /etc/mail
$ mkdir certs
$ /usr/share/ssl/miscCA -newca
次に、ビルト処理が多数の質問をして来る:
CA の作成・・・
1024 ビット RSA プライベートキイの作成
.++++++
..++++++
'./demoCA/private/./cakey.pem' に対し新規プライベートキイを書く
PEM パスフレーズ:秘密パスワードを入力
検証−PEM パスフレーズ:秘密パスワードを入力
-----
これで、自分の認証要求に組み込まれる情報の入力を要求される。
入力するのは、Distinguished Name 又は DNと呼ばれるものだ。
フィールドは極めて小さいが空白を残すことが出来る。
フィールドによっては、初期設定がある。
'.' を入力すると、空白のままになる。
-----
国名(2文字コード) [GB]:US
US
州名又は県名(全名称) [Berkshire]:Pennsylvania
Elkins Park
地方名 (市など) [Newbury]:Philadelphia
Philadelphia
組織名 (会社名など) [○○株式会社]:DiaperChanger
DiaperChanger
部署名(課名など) []:
共通名(自分の名又はサーバのホスト名) []:mike.localhost.com
mike.localhost.com
E-メールアドレス []:mchirico@comcast.net
次に ディレクトリ "demoCA" を "CA" に移動して0700のアクセス権を"private"に適用する。
$ mv demoCA CA
$ cd CA
$ chmod 0700 private
次に "sendmailssl.cnf"を作成する
$ cp /usr/share/ssl/openssl.cnf sendmailssl.cnf
"sendmailssl.cnf"に以下の変更をしなければならない。このファイルで
dir = ./demoCA # Where everything is kept
を
dir = /etc/mail/certs/CA # Where everything is kept
に変更する必要がある。
ステップ 3:
"sendmail.mc" を変更する
次に "/etc/mail/sendmail.mc" を次のように変更する:
MASQUERADE_AS(`comcast.net')dnl
FEATURE(masquerade_envelope) FEATURE(genericstable, `hash -o
/etc/mail/genericstable')
GENERICS_DOMAIN_FILE(`/etc/mail/genericsdomain')dnl
上の二行目に注意。一行にしなければならない。次の場所で、サンプル "sendmail.mc" をダウンロードするのが最善:
MASQUERADE_AS('comcast.net') は、 "chirico" の下のリターンメールを "chirico@comcast.net" と解釈する。それでも、ステップ4で示した "chirico" から "mchirico" への転換は必要。
変更は、次のように "m4" を通じてランされるまで有効にならない:
$ m4 /etc/mail/sendmail.mc > /etc/mail/sendmail.cf
STEP 4:
"genericstable" が必要なので、次のように作る。名称の間に空間が一つある:
これが"chirico" を "mchirico"に変換する。
次に、ハッシュテーブル "/etc/mail/genericstable.db" を構築する必要がある。
$ makemap -r hash genericstable.db /etc/mail/genericsdomain
ステップ 6:
"/etc/mail/sendmail.mc" で、以下の「定義」行がアンコメントされていて、 `smtp.comcast.net' が追加さていることを確かめる。
dnl # 発信メールを外部メールサーバを通じて送る
dnl # 必要があるときは、以下の行をアンコメントして編集する:
dnl #
define(`SMART_HOST',`smtp.comcast.net')
ステップ 7:
sendmailをスタートし直す。Redhaには次のコマンドが働く:
$/etc/init.d/sendmail restart
ステップ 8:
接続をテストする:
mchirico@comcast.net... deliverable: mailer relay,
ステップ 9:
Procmaiを用いて簡単な迷惑メールフィルタを作る。
以下は、次を含む "/home/chirico/.forward" 例である:
"|exec /usr/bin/procmail"
Procmail は "/home/chirico/.procmailrc" でprocmail ルールを探す。以下はファイルのサンプルである:
#####################################################
# Procmail ファイル "/home/chirico/.procmailrc" のサンプル#
#####################################################
# 追加の例については、"man procmail" をおこなう。
#
PATH=/bin:/usr/bin:/usr/local/bin
MAILDIR=/var/spool/mail
DEFAULT=/var/spool/mail/chirico
LOGFILE=/home/chirico/MailBAG
#
#
:0 HB
* ^Content-Type.*image.*gif.*name.*\.gif
* ^Content-Disposition.*attachment.*filename.*\.gif"
{
:0
/dev/null
}
参考資料:
この文書の最新版:
筆者の"sendmail.mc" のコピイは以下にある:
筆者の ".fetchmailrc" のコピイは以下にある:
筆者の"site.config.m4" のコピイは以下にある:
筆者の "genericstable" のコピイは以下にある:
筆者の "genericsdomain" のコピイは以下にある:
優良な参考書:
"Sendmail Cookbook: Administering, Securing & Spam-Fighting", Craig Hunt, 2004, O'Reilly.
最新版へのリンク:
投稿者:Nikhil Bhargava、 07/10/2004 - 08:48. 記事
Linux Kernelのコードは、プロセス、ボトムハーフ及び割込の三つの文脈のうち一つで走る。プロセス文脈では、ユーザプロセスに代わりに直接実行する。システム呼出は全部、プロセス文脈で走る。割込ハンドラは割込文脈で走る。Softirqs, Task let及びTimerは、ボトムハーフ文脈で走る。これらの機能は、SMP拡張性を良くするため導入された。開発の殆どが,対称的多重処理の分野でおこなわれているからである。現存のボトムハーフ(Linux 2.3.42以前)は、Linux 2.5.40で、taskletの特別型としてやり直され、そのセマンチックを維持した。この記事では、ボトムハーフ、tasklet及びソフト及びハードの割込ハンドラなどSMPシステムの文脈で混同され易いものなどLinux kernelにおける新機能を簡単に紹介する。
Softirq
これらは、OS又はシステム呼出の最後にkernelが呼び出されるか又は、ハードウエア割込ハンドラで呼び出される。これらをユーザが呼び出すことはなく、迅速な実行が必要なとき呼び出される。これらは32個の列挙softirqsで、従属関係全部を了解しているのでない限り開発者はリストに新しいものをリストに追加しない方が良い。SMPシステムにおいては、同一のsoftirqを二つの異なるCPUで走らせることが出来るが、softirqは一般的に再入可能ではない。これらは次のシステム呼出に際し現在CPU上で有効/無効にすることが出来る:
void local_bh_disable ();
void local_bh_enable ();
これらはボトムハーフとtaskletを実行するため用いられる。
Hardirq
ハードウエア割込ハンドラは、ハードウエア割込受領に際し直接呼び出される。これらは、走る前に自分の特定CPUの上の割込全部を無効にする。ユーザから走らせるのでないので極めて速く、持続時間が短い。通常、これらは非常に緊急の作業をおこない、他のsoftirq 又は taskletが大量のI/O活動をおこなうようスケジュールする。これらは次のシステム呼出により有効/無効にすることが出来る:
void local_irq_disable ();
void local_irq_enable ();
ボトムハーフ
ボトムハーフは、作業を割込動作から遅らせて、アプリケーションに確定応答時間を与え、システムのリアルタイム能力を強化する。これらは時間を必要とする。これは基本的に割込ルーチンを、ハードウエア割込を受けるトップハーフと、大量のプロセスをおこなうボトムハーフに分離する。ネットワーク作業、キイボード、マウス、コンソール、SCSIはすべてボトムハーフを直接使用する。SMPシステムでは、同時に一つのボトムハーフしか走らせることが出来ない。ボトムハーフに続いて使用される殆どはタイマーBHである。
これらは次のシステム呼出により現在CPU上で有効/無効にすることが出来る:
void local_bh_disable ();
void local_bh_enable ();
しかし、単一スレッドのボトムハーフは著しい改良が出来ないので、殆どのボトムハーフは現在softirqs 又は taskletに置き換えられていて、ネットワークプロトコルの性能はSMPアーキテクチャ上にスタックされる。
Tasklet
Taskletは、Linux kernelへの新しい追加で、性質はsoftirqに似ているが、多少の相違がある。taskletは動的に作られ、同時には一つのCPU上でのみ走ることが出来る。これらは、他のtaskletを同時に走らせることができるので、SMPに馴染む。taskletはsoftirqよりCPU親和性が弱い。一般的に次ぎのように宣言される:
DECLARE_TASKLET (name, func, data);
これはタイプのスタチックレコードを作成する。
struct tasklet_struct;
taskletファンクションは次のようになる
void func (unsigned long data);
例外状態を扱うため、個別 tasklet を有効無効にすることが出来る。
void tasklet_enabled (struct tasklet_struct *t);
void tasklet_disabled (struct tasklet_struct *t);
保証
この記事で示した情報は、筆者の知識の限り真正であるが、相違や矛盾がある時の、最終判断はLinuxソースコードである。
投稿者: Victor Castro、 07/13/2004 - 12:21. 記事| 一般|ハウツー
緒言
任意のコードを走らせる能力は、特にバッファ超過などを探求するため、極めて有用である。このような任意コードを走らせるにはシェルコードと呼ばれるものを使用する。シェルコードは、16進形式で掛かれる機械語で、通常平文バイナリから誘導される。シェルコードは機械コードなので、移植可能ではなくOSとCPUアーキテクチャにより変動する。シェルコードは、コード実行の有用な方法であるので、位置無関係機械語コードであることが多く、通常はヒープ又はスタックに置かれるデータバッファの中にある。この記事では、自分のシェルコードを書く方法と、それをCプログラムで実行する方法を述べる。シェルコードの落とし穴と修復方法も述べる。先ず、最初のシェルコードを書いてシェルコードを作る方法を見よう。
必要条件
シェルコードを書くのに必要なことは、基本的にアセンブリ言語とCプログラム言語の知識である。作業用のツールも必要である。ここでは、プログラムのアセンブルにNetwide Assembler 即ちNASM を用い、それらのディスアセンブルにndisassemを用いる。またgccを用いてユティリティプログラムをコンパイルする。この記事では、Linuxを走らせるx86に集中する。最初のシェルコードは、簡単で平凡な例を含み、読者をシェルコードの世界に誘う。パラメータを含まない簡単なシステム呼出作業、ポーズシステム呼出、から始める。以下をshellcode.cと言うファイルにコピイされたい。
/***************** shellcode.c *****************/
#include /* fprintf,etc.. */
#include /* perror */
#include
#include /* struct stat */
#include
/* Prototypes */
void error(char* msg);
void print(char* msg);
void usage(char* pname);
void shellcode(void);
void execute(void);
/* Globals */
FILE *file;
void *code;
void (*fptr)(void);
struct stat sbuf;
long filelen;
int indx,length;
int m = 15; /* max # of bytes to print on one line */
int args;
/* Main */
int main(int argc, char* argv[])
{
/*
* Open, Read, and Close Shellcode File
*/
if(argc < 3) { usage(argv[0]); }
if(stat(argv[2],&sbuf)) { error("Couldn't 'stat' File"); }
filelen = (long) sbuf.st_size;
if(!(code = malloc(filelen))) { error("Couldn't Allocate Memory"); }
if(!(file = fopen(argv[2], "rb"))) { error("Couldn't Open File"); }
if(fread(code, 1, filelen, file) != filelen) { error("Couldn't Read File"); }
if(fclose(file)) { error("Couldn't Close File"); }
while ((args = getopt (argc, argv, "e:c:")) != -1)
{
switch (args)
{
case 'e':
execute();
break;
case 'c':
shellcode();
break;
default :
usage(argv[0]);
}
}
return 0;
}
void error(char* msg)
{
perror(msg);
exit(1);
}
void print(char* msg)
{
fprintf(stdout,"%s\n",msg);
fflush(stdout);
}
void usage(char* pname)
{
fprintf(stderr,"\nConvert Code: %s -c <filename>",pname);
fprintf(stderr,"\nExecute Code: %s -e <filename>\n\n",pname);
fflush(stderr);
exit(1);
}
void shellcode(void)
{
fprintf(stdout,"\n\nchar shellcode[] =\n");
length = m;
for(indx = 0; indx = m)
{
if(indx){ fprintf(stdout,"\"\n"); }
fprintf(stdout,"\t\"");
length = 0;
}
++length;
fprintf(stdout,"\\x%02x", ((unsigned char *)code)[indx]);
}
fprintf(stdout,"\";\n\n\n");
/* Print out C Program */
fprintf(stdout,"int main(void)\n");
fprintf(stdout,"{\n\tvoid (*code)();\n");
fprintf(stdout,"\tcode = (void*)shellcode;\n");
fprintf(stdout,"\tcode();\n");
fprintf(stdout,"}\n\n\n");
}
void execute(void)
{
print("Executing Shellcode ...");
fptr = (void (*)(void)) code;
(*fptr)();
}
/***************** shellcode.c *****************/
次のコマンドを用いてプログラムをコンパイルする
$>gcc -o shellcode shellcode.c
今、構築したのは基本的に、普通のバイナリを読み、シェルコードに変換してCプログラムに埋め込むか、又はこのシェルコードに対するファンクション・ポインタを使ってコード自体を実行するツールである。プログラムがシェルコードを作成する方法は、生のバイナリファイルを読み込んで16進表記でstdoutに出力する。-cオプションにより、コンパイルすることの出来るCプログラムが出力され、-eオプションにより、コードが実行される。このツールを用いると、自分の最初のシェルコードを書く準備が整う。
簡単な例
好みのテキストエディタを開いて、以下を pause.Sと言うテキストファイルに書込む。
;################# pause.S #################
BITS 32
xor eax,eax ; eax レジスタをクリヤ
mov al,29 ; pauseのための syscall番号
int 0x80 ; Kernel呼出
;################# pause.S #################
次のコマンドを用いてコードをコンパイルする
$>nasm -o pause pause.S
ここで行なったことは、nasmアセンブラを用いて我々の簡単なプログラムをコンパイルし、pause()システムを呼出すバイナリプログラムを作ることである。コードをそのまま実行すると、これは完全なELFエグゼクタブルではないので、失敗する。このコードを実行する最も速い方法は、前にコンパイルしたシェルコードツールを使うことである。
$>./shellcode -e pause
Executing Shellcode...
個のプログラムは、 Ctrl-Cを押すまで、そこに居座っている筈である。コードが働くことが分かったので、シェルコードを出力して普通のバイナリをディスアセンブルしよう。その後で、コードを自分のCプログラムに埋め込む。
$>./shellcode -c pause
char shellcode[] =
"\x31\xc0\xb0\x1d\xcd\x80";
$>ndisasm pause
00000000 31C0 xor ax,ax
00000002 B01D mov al,0x1d
00000004 CD80 int 0x80
作成されるシェルコードは、実質的に ndisasmプログラムでディスアセンブルしたバイナリコードと同じである。ここで、prog.cと言う名の次のCプログラムを用いてテストして見よう:
/***************** prog.c *****************/
char shellcode[] =
"\x31\xc0\xb0\x1d\xcd\x80";
main(){
int (*code)();
code=shellcode;
code();
}
/***************** prog.c *****************/
ここでは、キャラクタアレーを宣言して、それをシェルコード・ユティリティにより我々が作ったシェルコードに初期化する。main() では、codeと言うファンクションへのポインタを宣言する。次いで、コントロールをcode()ファンクションに渡すと、これがシェルコードを実行する。次のコマンドを用いてprog.c をコンパイルし、プログラムを実行する:
$>gcc -o prog prog.c
$>./prog
ここでも、プログラムは Ctrl-Cが押されるのを待つ。これが意味するのはは、我々のシェルコードが働くことである。このプログラム命令を16進値として文字アレーに格納市、必要に応じてこれを実行する。例は瑣末に見えるが、可能性は無限である。任意のコードを実行する能力があるので、沢山のことが出来る。次に、落とし穴幾つかとシェルコードの仕掛けを見る。
NULL バイトの回避
NULL バイトは、シェルコードプログラム作成者の誰に取っても致命的な敵である。これは、NULL バイトが文字列の終わりを意味する文字列デリメータだからである。これは、コードを使ってバッファオーバーフローを検索するとき、具合が悪い。コードがNULLバイトを含んでいると、検索が出来ない。オーバーフロー検索の詳細は、この記事の範囲を出るので、詳しくは参考文献を参照されたい。シェルコードプログラム作成でNULLコードを作ってしまう最も普通の間違いは、大きいレジスタの中に小さい値を入れることである。例としてexitシステム呼出を見る:
;################# exit.S #################
BITS 32
xor eax,eax ; eax をゼロにする
mov eax,0x01 ; exit()のためのシステム呼出番号
xor ebx,ebx ; exit(0);のためのebxをゼロにする;
int 0x80 ; Kernel を呼出す
;################# exit.S #################
この例においては、8ビット値0x01を32ビットレジスタeaxに入れている。このため、図1に示すように、シェルコードに三つのNULLバイトが出来る。
研究のためこのコードをアセンブルしてディスアセンブルする:
$>nasm -o exit exit.S
$>./shellcode -c exit
char shellcode[] =
"\x31\xc0\xb8\x01\x00\x00\x00\x31\xdb\xcd\x80";
$>ndisasm exit
00000000 31C0 xor ax,ax
00000002 B80100 mov ax,0x1 ; NULL バイト1個
00000005 0000 add [bx+si],al ;2 NULL バイト2個が出来る
00000007 31DB xor bx,bx
00000009 CD80 int 0x80
ここで、シェルコードにNULバイト (\x00) が三つあることが分かる。この問題を救済するには、値の挿入又は移動に際して常に最小のレジスタを使わなければならない。exit.Sプログラムの改良版を示す:
;################# exit2.S #################
BITS 32
xor eax,eax ; eax をゼロにする
mov al,0x01 ; システム呼出番号を8-ビットal レジスタに移動
xor ebx,ebx ; exit(0);のためのebxをゼロにする
int 0x80 ; Kernel を呼出す
;################# exit2.s #################
exit2.S をもう一度アセンブルしてディスアセンブルし、EAXレジスタダンプに関する次のリストを見る:
$>nasm -o exit2 exit2.S
$>./shellcode -c exit2
char shellcode[] =
"\x31\xc0\xb0\x01\x31\xdb\xcd\x80";
$>ndisasm exit2
00000000 31C0 xor ax,ax
00000002 B001 mov al,0x1
00000004 31DB xor bx,bx
00000006 CD80 int 0x80
これで、NULLバイトのない正しいシェルコードが得られる。シェルコードにNULLバイトがないことを常にチェックして問題を避ける。また、NULLバイトだけがデリメータではない。文字列に使われるバックスラッシュその他のデリメータもまた、危険であることに注意されたい。
位置無関係のコード
シェルコードを書くことは、普通のアセンブリコードを書くのとは異なる。どのアドレスにいるか分からないので、データにアクセスすることが出来ないし、ましてメモリアドレスをハードコードするのは不可能である。これは重要な欠点だが、常に対策がある。シェルコードで文字列又はデータを使う最も容易な方法は、次のコードを使うことである:
BITS 32
jmp short dummy
__start:
;レジスタをpop
;ここに、文字列を用いる
;アセンブリ命令を
;入れる
dummy:
call __start
db 'Simple String'
このコードがするのは、ラベルdummyにjmp shortして、そこから__start ラベルを呼出すことである。startラベルに行くと、レジスタをpopすることが出来るので、それによりそのレジスタに我々の文字列の位置をを含ませる。これは、コードを実行する位置が分からないとき、極めて有用な工夫である。これが分かったので、シェルをspawnするもっと有用な例に入る。
もっと有用な例
exeve() システム呼出を用いてプログラムを実行する。このプログラムは、シェルをspawnするのに使うことが出来るので、シェルコードを用いるとき極めて価値がある。execve()呼出に成功するとファンクションはreturnしないので理想的でもある。execveシステム呼出に対するファンクション原型を示す:
int execve(const char *filename, char *const argv [], char *const envp[]);
Linux でシステム呼出を実行するとき、アセンブリ言語がパラメータを取る方法であることを覚えておくと良い。Linux Kernel ソフトウエアinterrupt(int 0x80)を使う前にレジスタを設定しシステム呼出を呼出す方法を示す。
EAX = Number of the Systemcall
EBX = Argument 1
ECX = Argument 2
EDX = Argument 3
ESI = Argument 4
EDI = Argument 5
パス/bin/shにあるshシステム呼出を実行する方法に関する例を見てみる。この例は、前節で述べたデータアドレッシング対策を使用している。 execveシステム呼出を次の方法で利用する:
execve("/bin/sh","/bin/sh",NULL);
最初の引数は文字列"/bin/sh"へのポインタである。第二の引数は "/bin/sh"へのポインタである。第三の引数は、システム呼出に、パラメータを用いておこなったことを告げるNULLへのポインタである。アセンブリコードは次のようになる:
;################# execve.S #################
BITS 32
jmp short dummy ; jmp の仕掛け
start:
pop esi ; esi レジスタが文字列をポイントする
xor eax, eax ; eax レジスタをクリヤ
mov byte [esi + 7], al ; "/bin/sh" を終結
lea ebx, [esi] ; "/bin/sh" をebx レジスタに置く
mov long [esi + 8], ebx ;
mov long [esi + 12], eax ;
mov byte al, 0x0b ; execve()のためのシステム呼出番号
mov ebx, esi ; 第一引数:文字列 "/bin/sh"へのポインタ
lea ecx, [esi + 8] ; 第二引数:"/bin/sh"へのポインタ
lea edx, [esi + 12] ; 第三引数:NULLへのポインタ
int 0x80 ; Kernelを呼出す
dummy:
call start ; "/bin/sh"のアドレスを得るためのjmpの仕掛け
db '/bin/sh$XXXXNULL'
;################# execve.S #################
ここでもまた、前節で示したデータアドレッシング対策を用いて、文字列のアドレスを得ている。その後、execve() システム呼出のシステム呼出番号をalにmoveしそれにしたがってレジスタを設定する。このプログラムをアセンブルしshellcodeユティリティを用いてそれを実行しよう:
$>nasm -o execve execve.S
$>./shellcode -c execve
char shellcode[] =
"\xeb\x1a\x5e\x31\xc0\x88\x46\x07\x8d\x1e\x89\x5e\x08\x89\x46"
"\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\xe8\xe1"
"\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68\x24\x58\x58\x58\x58"
"\x4e\x55\x4c\x4c";
$>./shellcode -e execve
Executing Shellcode ...
sh-2.05b#
やった!我々のシェルコードを使ってシェルをうまく spawnした。
まとめ
この記事で、シェルコードとその働きを学んだ。また、自分の目的に使うためシェルコードを書いてデバッグする方法も学んだ。
情報源
ソースコード全部を入手出来る著者のウエブサイト:
http://www.geocities.com/victorhugo83
Linuxアセンブリ言語 情報源:
http://www.linuxassembly.org/
最高。趣味と実益の本棚:
http://www.phrack.org/show.php?p=49&a=14
Netwide アセンブラ
http://nasm.sourceforge.net
SMPシステムにおけるロック構造としてのSpinlocks
投稿者: Nikhil Bhargava、07/15/2004 - 20:24. 記事|一般
Spinlocksの紹介
共有重要データをロックするためSMP関連の構造を読んでいて、spinlocksが効果的なSMPロック構造であることを見出した。そこで初心者にSpinlocksを紹介するためこの記事を書く。Spinlocksは、単一プロセッサシステムと同時にマルチプロセッサシステムの双方において重要データをロックするため用いることが出来る。しかしこれは、global configオプションCONFIG_SMP をYに設定するときのみ利用することが出来る。次のように用いられる。
spinlock_t xxx_lock=SPINLOCK_UNLOCKED;
............................
............................
unsigned long flags;
............................
spin_lock_irqsave (&xxx_lock, flags);
............................
............................
....critical region.........
............................
............................
spin_unlock_irqsave (&xxx_lock, flags);
これは割込をすべてローカルに無効にし、上述の重要部部を実行している正確に1個のスレッドを意味するこの特定CPUに対し単一のglobal lockを与える。単一プロセッサシステムの場合は、上述のシーケンスは次のようになる。
unsigned long flags;
...........................
save_flags (flags);
cli ();
............................
....critical region.........
............................
............................
restore_flags (flags);
spinlocksには一つの限界つまり欠点がある。上述のコード順はローカルCPU上で割込を無効にすることは出来るが、この領域が別のCPUの前後関係上でロックされていないときは、データ不一致を生じる。
Spinlocksは、共有データを変更する明確に分離され、互いに全て無関係の領域に、高度に組織化されたコード内で使用しなければならない。例えば、デバイスドライバルーチンなどである。その上、同一タイプのオブジェクトに多重にロックを用いることは、効率が悪くなるデッドロックを生じるので、お薦めしない。既に取得済みのロックによりガードされている領域内に追加してロックを取得することは危険で、確実にデッドロック状態を生じる。
Reader-Writer spinlocks
Reader-Writer ロックは、殆どのプロセスが共有データオブジェクトの読取だけを必要とし、書込は稀にしか必要としない場合に最良である。多重読取プロセスは重要領域であるだろうが、プロセスがオブジェクトを変更したいときは、排他的書込ロックを要求して競争取得しなければならない。排他的書込ロックは、読取プロセス全部がその読取ロックを解除し、重要領域では誰も読取していないとき、kernelが与える。
read/write ロックを用いるルーチンは次の通りである:
rwlock_t xxx_lock=RW_LOCK_UNLOCKED;
............................
unsigned long flags;
............................
read_lock_irqsave (&xxx_lock, flags);
............................
............................
....critical region.........
............................
............................
read_unlock_irqsave (&xxx_lock, flags);
rwlock_t xxx_lock=RW_LOCK_UNLOCKED;
............................
unsigned long flags;
...........................
write_lock_irqsave (&xxx_lock, flags);
............................
............................
....critical region.........
............................
............................
write_unlock_irqsave (&xxx_lock, flags);
Upgradable はこれに対する迅速で汚い解決策になるが、深刻な不一致と問題を生じると考える。
Spinlocksの簡潔版
XXX_irqxxx (イネーブル/ディスエーブル割込ルーチン) の型のSpinlocksは、作動が極めて遅い。これは、割込を無効にするため是非必要なとき、又はスピンロックにより保護されるコードが「割込コンテキスト」にあるときのみ、使用しなければならない。そのコードが常に「プロセスコンテキスト」で走ることを開発者が確信するときは、スピンロックの非割込版が最良である。
spinlock_t xxx_lock=SPINLOCK_UNLOCKED;
............................
spin_lock (&xxx_lock);
............................
............................
....critical region.........
............................
............................
spin_unlock (&xxx_lock,);
しかし、spinlokのこの版を割込コンテキストで走らせるべきコードに使うことは、デッドロックを招く。
投稿者:Crouse 、07/21/2004 - 00:37. 記事| 興味
殆どの人がLinuxを知っており、殆どの人がKnoppixについて聞いたことがある。Knoppixは、Linuxの素晴らしい変形で、ハードドライブを全く使わないでCDROMからLinuxを走らせることが出来る。これら「生Linux」ディストリビューションには沢山の変形かある。それらは全て同じ原理で働く。CDROMにディスクを入れてブート仕直す。ハードドライブには全く触れないで、OSがCDROMとRAMから静かに走る。多くの変形では、情報全部を直接コンピュータ上のラムにプッシュすることを、ブートプロンプトからシステムに命じることが出来る。このブートの後、全てがRAMに入るので、CDROMを取り外しRAMだけからOSを走らせることが出来る。ハードドライブもCDROM読取/書込アクセスも要らない。これによりCDROMを、音楽CDの再生、焼き付け、などに使用することが出来る。「生」Linuxをブートするには、BIOSの順序でハードドライブの前にCDROMをリストしなければならない。殆どのコンピュータは、そのような設定になっている。そうでないときは、BIOS立ち上げ順序を変更して「生」Linux CDを働かせなければならない。
「生」Linux新版の多くは、ハードドライブ、USBペンドライブ、フロッピイ、CD-RW、又はその他の媒体に、ダウンロードした追加物又は作成ドキュメント全部と共にセーブすることが出来る。小さいバージョンの多くは、USBペンドライブから立ち上げる能力を有する。これら小さいLinuxには、ハードドライブにインストールする他のLinuxと同じように沢山の用途がある。多くの場合、扱う楽しみがあるし、問題解決のツールとなる。物事が行き詰まったとき、道具箱にこれらの一つがあると便利だ。またLinux の世界に入るための良い方法にもなる。試して見るのに安全で面白い方法だ。自分の現行システムを壊さないでLinuxに着手する方法だ。
筆者が本当に論じたいのは、大きさが210MB以下の「生」Linuxディストリビューションだ。これらは大きい兄貴分のKnoppix ほどは知られていない。サイズが小さいので、小さい3" CD-Rに収容することが出来る。それらをシャツのポケットに入れられるので、運び易い。小さいからと言って馬鹿にしてはいけない。小さいが巨大な力を発揮する。最大限の力を発揮したときの、ほんの表面をこするにすぎないと思うが、幾つかを紹介したい。これから説明する四つの小さいディストリビューションは素晴らしいもので、読者のバンド幅に収容する価値がある。
先ず、一番小さいものから始める。
***
名称:Damn Small Linux.
現行バージョン: 0.7.2
サイズ:46.9M
Damn Small Linuxが本当に素晴らしいことの一つは(名前が面白い他に)、「クレジットカード」CDに入ることだ。これらは3" 185-210mb CD-Rより小さい。問題なくポケットに入る。規定値ウェブブラウザはDilloだ。これでも良いが、幾つかのウエブペイジを殺すので、感心しない。多分、私が使いこなしていないからだろう。幸い、クリックするだけでFireFoxウェブブラウザをダウンロードすることが出来る。このパケットはこのサイズの中に沢山の機能を含む。扱って面白いし役に立つツールだ。
***
名称:Feather Linux
現行バージョン:0.5.3
サイズ: 61.4M
これは少数のアプリケーションが違うだけでDamn Small Linuxに良く似ているが、極めて小さい。ダイアルアップして「生」Linuxを楽しみたいが、電話の使用を長い間断念したくない人に適している。DSLなどクレジットカード型のCD-Rに焼き付けたことはにが、これを走らせるには大きい 3" 185 or 210 MB CD-R を使う必要があるだろう。
***
名称:Slax
現行バージョン: 4.1.2
サイズ:188M
これは四つのうちの本命だ。Kopeteの好きなxchatを除外したのが、私を酔わせる。全体として、これはslackwareに基づく極めて高級なディストリビューションだ。Slaxで極めて素晴らしいことの一つは、ワープロ、表計算ソフト、電卓、スライド作成ソフト、住所録、オーガナイザなど、殆どの「オフィス型」プログラムが揃っていることだ。絶対にダウンロードの価値がある。
***
名称:Morphix Combined-Light GUI
現行バージョン:0.4-1
サイズ: 203.2M
Morphix は、別のCDディストリビューションKnoppixの子孫だ。これが今のところ筆者のお気に入り「生Linux」だ。Morphixの個のバージョンが気に入らなければ、他の選択肢もある。それらはいずれも、以下のダウンロードペイジから入手することが出来る。
Morphix LightGUI - 小型高性能
Morphix Gnome / Morphix KDE -デスクトップ強力ユーザ用
Morphix Gamer - 子供用
Morphixのこのバージョンには生Linuxディストリビューションに筆者の求める全てがあった。筆者は主に、特殊アプリケーションを探していたが、これに整っていた。Firefox ウェブブラウザ、Xchat IRC クライアント、vncviewerで、これはGUIとしてXFceを用いる。また、筆者が個人的に必要とする特殊アプリケーションもあった。全体として、筆者はこのバージョンに魅せられたが、読者によっては別のディストリビューションで満足する人もあるだろう。Linuxの良いところは、選択肢が多いことだ。
退屈したら、Morphix Gamer をダウンロードすると良い。大変素晴らしい !!
***
その他の佳作;
名称:SystemRescueCd
現行バージョン: SystemRescueCd-x86-0.2.14
サイズ:102M
名称:Lamppix Mini CD
現行バージョン:
サイズ:111M
名称:Linux LiveCD Router
現行バージョン: 1.9.6
サイズ: 93M
以下には、便宜のため最小から最大まで分類した「生Linux」の大きいリストがある。
自分のコンピュータをDVDプレーヤにしたいときは、
http://movix.sourceforge.net/ をチェックされたい。MoviX プロジェクトは、CDから立ち上げMPlayerを通じてマルチメディアファイルを再生するソフトウエア全部を含む別々の小さいLinux CDディストリビューション三つのシリーズである。
おしまい・・・・暫くは忙しくなるかな
活発な米国Linux ユーザーグループ
コマンドプロンプトからのGPCメール発信
投稿者: mchirico 、07/21/2004 - 16:27. 記事|一般|ハウツー|セキュリティとGPC/PGP
適切な「pgp暗号化」mime型を用いるFTP自動化、E-メール着信通知、コマンドプロンプトからの暗号化GPC e-メールの発信、及びパスワードを用いないコマンド行からのMySQL起動の詳細を述べる。
この文書の最新版は
にある。
この文書に付属するプログラムとスクリプトは、
にある。
スクリプト 1:
FTP自動化:
"ftp" のためのパスワードは、"~/.netrc" に記憶されている。三つのログインを規定する例を示す。 "anonymous" とパスワード user@siteを用いる初期設定である。sourceforge.netアプロード用の別のパスワード、及びログイン"bobby" とパスワード "b0bb13"はコンピュータ192.168.1.35用である。
$ cat ~/.netrc
default login anonymous password user@site
machine upload.sourceforge.net login anonymous password
m@temp.com
machine 192.168.1.35 login bobby password b0bb13
このファイルを作ったら次のように保護しなければならない:
$ chmod 0400 ~/.netrc
次に、もし存在しないときは、ホームの下に二つのディレクトリ "/faq/unix-faq" を作る。これは、"mkdir" を "-p"オプションで用いる利点で、これによりサブディレクトリの層幾つかを作る、そうでないと存在するディレクトリ全てはエラーを戻さない。
#!/bin/bash
#
# Sample ftp automated script to download
# file to $dwnld
#
dwnld=~/faq/unix-faq
mkdir -p $dwnld
cd $dwnld
ftp << FTPSTRING
prompt off
open rtfm.mit.edu
cd /pub/usenet-by-group/news.answers/unix-faq/faq
mget contents
mget diff
mget part*
bye
FTPSTRING
注記:変数ダウンロードの初期指定には引用符を用いない。引用符がないと、ユーザchiricoのため、ユーザのホーム "/home/chirico/faq/unix-faq" を参照する。
$ dwnld=~/faq/unix-faq # これが良い。 /home/chirico/faq/unix-faqを参照
$ dwnld="~/faq/unix-faq" # 良くない。 現在位置のディレクトリ '~' を参照
スクリプト 2:
findの使用
以下は、現在ディレクトリのファイル>20k全部をfindする。
$ find . -size +20K
以下は "/CVS" とその下のファイルを除いて、全てのファイルをfindする。更に、このfaindでは"~" で終わるファイルを無視するが、 "here~is"はピックアップする。
$ find . \( -iregex '.*/CVS' -o -iregex '.*~' \) -prune -o -print
上のコマンドは、"test" ディレクトリの下の全てのファイルのため "tar.gz" を作るのに用いることが出来る。"-H ustar" は、tarのgnu/posixのためである。
$ find ./test \( -iregex '.*/CVS' -o -iregex '.*~' \) -prune -o -print | cpio -o -H ustar |gzip > data.tar.gz
だが、一寸待て。"data.tar.gz"に、 "./test2"の下にあるものなど、余分なファイルを追加したいことがあるだろう。
$ gunzip data.tar.gz
$ find ./test2 \( -iregex '.*/CVS' -o -iregex '.*~' \) -prune -o -print | cpio -o -H ustar --append -F data.tar
$ gzip < data.tar > data.tar.gz
この最後のコマンド "$ gzip < data.tar > data.tar.gz" は、"$ gzip data.tar"だけを用いておこなうことも出来る。しかし、短いコマンドは、もっと追加するとき役に立つことのある data.tarを削除してしまう。
その中の '*.c' files with the 'current->signal->tty' をすべて、エラーを無視してfindする。
$ find . -iname '*.c' -exec grep -H 'current->signal->tty' {} \; 2>/dev/null
./arch/i386/mach-voyager/voyager_thread.c: current->signal->tty = NULL;
./arch/sparc64/solaris/misc.c: current->signal->tty = NULL;
./arch/ia64/kernel/unaligned.c: tty_write_message(current->signal->tty, buf);
./drivers/net/slip.c: if (sl->tty != current->signal->tty && sl->pid != current->pid) {
...
上で注意すべきは、ファイル名が左に示してあることだ。このような内容は、kernelの変更を見出すのに良い。それはさておき、Linux kernelの2.6+バージョンでは、"current->tty" を今は "current->signal->tty" で置き換えている。
grepされるテキスト "-B" の前に3行、 "-A"の前に2行欲しいとする。そのときは、次のように、後のために "-A"を、前のために "-B" を用いる。
$ find . -iname '*.c' -exec grep -H -A 2 -B 3 'current->signal->tty' {} \; 2>/dev/null
./kernel/exit.c- exit_mm(current);
./kernel/exit.c-
./kernel/exit.c- set_special_pids(1, 1);
./kernel/exit.c: current->signal->tty = NULL;
./kernel/exit.c-
./kernel/exit.c- /* Block and flush all signals */
INODES.
'/' 又は '\0' を除く任意の文字を用いて、ファイル又はディレクトリを作ることが出来る。
$ touch 'this~\nis one big file here'
ファイルのinodeを得るには
$ ls -il th*
75489 -rw-rw-r-- 1 chirico chirico 0 Jul 20 15:28 this~\nis one big file here
findは、次のように特定のinodeを探すことが出来る:
$ find . -inum 75489
そのinodeを用いてこのファイルを簡単に削除するには、
$ find . -inum 75489 -exec rm {} \;
FIND とREPLACE
別の用途
ルートから始めて、全てのファイルをfindする。エラーを無視して< n*24 時間以前を査定した。ここで、 n=-1である。> 24については n=+1に設定すると、「正確に」24時間以前n=1になる。
$ find / -atime -1 2>/dev/null
スクリプト 3:
Eメール着信通知
以下のファイル"data" を想定する
$ cat data
1 one
2 two
3 three
4 four
オンラインとカラムで"awk" はゼロである。
$ awk '/3/ { print $2 }' data
three
また、システムコマンドも走らせることが出来る。以下は、 "wc" ワードカウントを用いる例である。
$ awk '/3/ { print $2| "wc" }' data
1 1 6
この次のコマンドは、コンピュータ名全部を示す"uname -a" を付けて、 io statsをe-メールする。日付は年月日と時間をナノ秒まで示す。
$ (uname -a;date "+%m.%d.%y %H:%M:%S.%N";iostat) | awk '{print $0|"mail -s \x27 iostats \x27
mchirico@comcast.net "}'
awkを用いると、変数と一緒に渡す必要があることがある。ユーザのためのプロセス全部を停止するスクリプトを考えてみよう。ここでは、シェルスクリプトに渡される第一引数がawkと一緒に渡されている。
#!/bin/bash
#
# このプログラムは、ユーザからのプロセス全部を停止する
# ユーザ名はコマンド行から読取る。
#
# 用途:kill9user <user>
#
kill -9 `ps aux|awk -v var=$1 '$1==var { print $2 }'`
スクリプト 4:
GPG 暗号化e-メールをコマンド行から送る。
PGPのGNU版GPGは、公開キイを用いてデータを簡単に暗号化する方法である。これは、理想的である。当事者間では、パスワードの送信や連絡がない。
例えば、以下のコマンドはfile.txtの中のデータを暗号化する。
$ openssl des3 -salt -in file.txt -out file.des3 -k secretPassword
しかし、受信者がこのファイルを受け取ったとき、ユーザは解読のため「秘密パスワード」を知る必要がある。さもないと、これをバッチ仕事でおこなうとき、パスワードが暴露される。
$ openssl des3 -d -salt -in file.des3 -out file.txt -k secretPassword
GPGは、この問題を回避する。パスワードの共有はない。GPGの詳細説明に関しては以下の参考文献を見られたい。
e-メールメッセージを暗号化してメッセージ本体にはめ込むのでは十分でない。 mime型を「pgp-暗号化」に設定するのでないと、ユーザはメッセージをコピイして貼り付けることを強制されるか、又はテキスト抽出のスクリプトを開発しなければならない。これは、メッセージをはめ込んで、バウンダリを付けて正しくmimeに設定する例である。e-メールをgpg又はpgp構成したユーザは、自動的にパスワードをプロンプトされる。
理想的には、スクリプトは次のように働く。
$ ls -l|./sndmailBash
fruser@isp.net touser@isp.net "Example ls -l cmd" 0xA11C1499
"ls -l" コマンドの内容が、メッセージ本体の中に暗号化されている。これはユーザ"fruser@isp.net" からで、ユーザ "touser@isp.net"宛てである。メッセージの題名は"Example ls -l cmd"でpgp キイ0xA11C1499で暗号化してある。
"sndmailBash" プログラムが、"Content-Type" を"sendmail -t" コマンドにパイプすることにより、これがpgp暗号化であるように設定する。 "-t" オプションは "From: ", "To: ", "Subject: "などの前置詞を解析する。バウンダリは静的であるが、独特でなければならない。
これをおこなう "sndmailBash" スクリプトを示す:
#!/bin/bash
# 著作権t GPL 2004
# 最終更新: Jul 21 14:14:10 EDT 2004
#
# サンプルペイジ:
# $ ./sndmailBash <from> <to> "<subject>" <gpgkey> < file
# 又は
# $ some command|./sndmailBash <from> <to> "<subject>" <gpgkey>
#
# 特殊例:
#
# 又は
#
# 上のコマンドはe-メールを "mchirico@comcast.net"から "mchirico@comcast.net"に
# " encrypted with the pgp key "0xA11C1499"の題名で送る.
#
# 以下のコマンドがgpaキイをリストする。
#
# $ gpg --list-keys
# /home/chirico/.gnupg/pubring.gpg
# --------------------------------
# pub 1024D/A11C1499 2004-07-15 Mike Chirico <mchirico@comcast.net>
# ^-------
# |___ add "0x" for "0xA11C1499"
#
# 明らかにこれは私のキイなので、正しい受信者キイを追加する
#
From=${1}
To=${2}
Subject=${3}
#Content=`cat | gpg -r ${4} --encrypt --armor `
Content=$(gpg -r ${4} --encrypt --armor )
/usr/sbin/sendmail -t <<EOF
From: ${From}
To: ${To}
Subject: ${Subject}
Mime-Version: 1.0
Content-Type: multipart/encrypted; protocol="application/pgp-encrypted";
boundary="B835649000072104Jul07"
Content-Disposition: inline
User-Agent: Mutt/1.4.1i
--B835649000072104Jul07
Content-Type: application/pgp-encrypted
Content-Disposition: attachment
Version: 1
--B835649000072104Jul07
Content-Type: application/octet-stream
Content-Disposition: inline; filename="msg.asc"
${Content}
--B835649000072104Jul07--
EOF
gpgに関してもっと知りたい人は下記にあるreference (TIP 86) を参照されたい
スクリプト 5:
コマンド行でMySQLを働かせる。
以下のスクリプトは、"test" データベース内の "exams"テーブルに問い合わせる。
$ mysql --skip-column-names -s -e "select * from exams" test
1 Bob 1 75
2 Bob 2 77
3 Bob 3 78
4 Bob 4 80
5 Sue 1 90
6 Sue 2 97
7 Sue 3 98
8 Sue 4 99
パスワードとユーザ名をプロンプトされるのを避けるため、ユーザーのホームディレクトリ"/home/chirico/.my.cnf" の中に ".my.cnf"を作って、以下と同様にユーザ名とパスワードを入れる。
[client]
user=user1
password=p@ssw0rd
他の方法では、誰かが "ps -aux" コマンドを行ったときパスワードを示すので、上述の方法を推奨する。
参考資料:
(この記事に関するプログラム)
(awk とshell)
(GPG)
http://www.gnupg.org/(en)/download/index.html
その他のヒント:
MySQL 参考書に関するヒント:
Fedora更新のあるRedHat 9 又は 8.0乃至2.6.x src kernel更新の参照:
ホームLinux ボックスのあるComcast E-メールに関するヒント: