Komut satırı argümanı olarak iletilen bir şifreyi nasıl gizleyebilirim?


43

Örneğin, bunun gibi görünen bazı özelliklerin kilidini açmak için bir parola girmesi gereken bazı eylemler gerektiren bir yazılım arka plan programı çalıştırıyorum:

$ darkcoind masternode start <mypassphrase>

Şimdi başsız debian sunucumla ilgili bazı güvenlik kaygılarım var.

Örneğin ne zaman benim bash geçmişimi araştırdığımda Ctrl+Rbu süper güçlü şifreyi görebiliyorum. Şimdi sunucumun tehlikeye girdiğini ve bazı davetsiz misafirlerin kabuk erişimine sahip olduğunu ve Ctrl+Rgeçmişimde parolamı bulabildiğini hayal ediyorum .

O bash tarihinin gösterilen edilecek olmadan parolayı girmek için bir yol var mı ps, /procbaşka bir yerde veya?


Güncelleme 1 : Arka planda parola geçirmemek hata veriyor. Bu seçenek değil.


Güncelleme 2 : Yazılımı veya geliştiricilerin asılması gibi diğer yararlı ipuçlarını silmemi istemeyin. Bunun en iyi uygulama örneği değil biliyorum ama bu yazılım dayanmaktadır Bitcoin ve tüm Bitcoin tabanlı istemciler hala tartışılıyor bu komutlar ve bilinen bir güvenlik sorunu (dinler json rpc sunucusu çeşit olan bir , b , c ) .


Güncelleme 3 : Arka plan programı zaten başlatıldı ve komutla çalışıyor

$ darkcoind -daemon

Bunu yapmak psyalnızca başlangıç ​​komutunu gösterir.

$ ps aux | grep darkcoin
user     12337  0.0  0.0  10916  1084 pts/4    S+   09:19   0:00 grep darkcoin
user     21626  0.6  0.3 1849716 130292 ?      SLl  May02   6:48 darkcoind -daemon

Bu yüzden komutları parola ile geçirmek, içeride psya da /prochiç görünmüyor .

$ darkcoind masternode start <mypassphrase>
$ ps aux | grep darkcoin
user     12929  0.0  0.0  10916  1088 pts/4    S+   09:23   0:00 grep darkcoin
user     21626  0.6  0.3 1849716 130292 ?      SLl  May02   6:49 darkcoind -daemon

Bu, tarihin nerede ortaya çıktığı sorusunu bırakıyor? Sadece içeride .bash_historymi?


1
İlk soru şudur: parolayı parola argümanı olmadan daemon'a başlatırsanız ne olur. Sadece bunun için ister mi?
MadHatter,

31
İşe yarayacak bir cevap olduğunu sanmıyorum. Bir parola isteme yetersizliği, servisteki önemli bir eksikliktir. Eğer özgür bir yazılımsa, bir programlayıcı edinin ve düzeltin; değişikliklerinizi yayınlamayı unutmayın. Özel bir yazılımsa, satıcıyı arayın ve onlara bağırın (bu hiçbir şeyi düzeltmez, ancak sizi daha iyi hissettirir).
MadHatter,

4
Belgelerinizi kontrol edin, bu sistem ortam değişkeninden bu şifreyi okumayı destekleyebilir.
Elliott Frisch

3
Şifre, servise komut satırında verilmemiş olsa bile, başka herhangi bir komutun komut satırında vermek hala problemlidir. Yalnızca ps çıktısında çok kısa bir süre görünür, ancak arka planda çalışan bir işlem onu ​​kaldırabilir. Ama tabii ki hala şifreyi almayı zorlaştırmakta fayda var.
kasperd

2
Bu sorunun cevaplarına bakın, tam olarak bu konuyla ilgileniyorlar.
dotancohen

Yanıtlar:


68

Gerçekten, bu olmalıdır uygulamanın kendisinden giderilecektir. Ve bu tür uygulamalar açık kaynak olmalıdır , böylece uygulamanın kendisinde konunun düzeltilmesi bir seçenek olmalıdır. Bu tür bir hata yapan güvenlikle ilgili bir uygulama başka hataları da yapabilir, bu yüzden ona güvenmem.

Basit aracı

Ama siz farklı bir yol mu soruyordunuz, işte bir tane:

#define _GNU_SOURCE
#include <dlfcn.h>

int __libc_start_main(
    int (*main) (int, char * *, char * *),
    int argc, char * * ubp_av,
    void (*init) (void),
    void (*fini) (void),
    void (*rtld_fini) (void),
    void (* stack_end)
  )
{
  int (*next)(
    int (*main) (int, char * *, char * *),
    int argc, char * * ubp_av,
    void (*init) (void),
    void (*fini) (void),
    void (*rtld_fini) (void),
    void (* stack_end)
  ) = dlsym(RTLD_NEXT, "__libc_start_main");
  ubp_av[argc - 1] = "secret password";
  return next(main, argc, ubp_av, init, fini, rtld_fini, stack_end);
}

Bunu derle

gcc -O2 -fPIC -shared -o injectpassword.so injectpassword.c -ldl

sonra sürecinizi ile çalıştırın

LD_PRELOAD=$PWD/injectpassword.so darkcoind masternode start fakepasshrase

Aracı kütüphanesi bu kodu mainuygulamanızdan gelen işlev yürütülmeden önce çalıştıracaktır. Son komut satırı argümanını ana çağrıya yapılan asıl parola ile değiştirir. Yine de basıldığı gibi /proc/*/cmdline(ve bu nedenle gibi araçlar tarafından görüldüğü gibi ps) komut satırı yine de sahte bir argüman içerecektir. Açıkçası, kaynak kodunu ve derlediğiniz kütüphaneyi sadece kendiniz tarafından okunabilir hale getirmeniz gerekecektir, bu yüzden bir chmod 0700dizinde en iyi şekilde çalışın . Parola komut çalıştırmanın bir parçası olmadığından, bash geçmişiniz de güvenlidir.

Daha gelişmiş aracı

Daha ayrıntılı bir şey yapmak istiyorsanız __libc_start_main, çalışma zamanı kitaplığı düzgün şekilde başlatılmadan önce yürütüldüğünü unutmayın . Bu nedenle, kesinlikle gerekli olmadıkça, işlev çağrılarından kaçınmanızı öneririm. İşlevleri kalbinizin içeriğine çağırabilmek istiyorsanız main, tüm başlatmalar bittikten hemen sonra, kendisini çağırmadan hemen önce yaptığınızdan emin olun . Ben şu Örneğin işaret Grubermensch teşekkür komut satırı argümanı olarak geçirilen bir şifre gizlemek için nasıl getirdi getpassdikkatimi.

#define _GNU_SOURCE
#include <dlfcn.h>
#include <unistd.h>

static int (*real_main) (int, char * *, char * *);

static int my_main(int argc, char * * argv, char * * env) {
  char *pass = getpass(argv[argc - 1]);
  if (pass == NULL) return 1;
  argv[argc - 1] = pass;
  return real_main(argc, argv, env);
}

int __libc_start_main(
    int (*main) (int, char * *, char * *),
    int argc, char * * ubp_av,
    void (*init) (void),
    void (*fini) (void),
    void (*rtld_fini) (void),
    void (* stack_end)
  )
{
  int (*next)(
    int (*main) (int, char * *, char * *),
    int argc, char * * ubp_av,
    void (*init) (void),
    void (*fini) (void),
    void (*rtld_fini) (void),
    void (* stack_end)
  ) = dlsym(RTLD_NEXT, "__libc_start_main");
  real_main = main;
  return next(my_main, argc, ubp_av, init, fini, rtld_fini, stack_end);
}

Bu şifre ister, böylece aracı kütüphanesini bir sır olarak saklamanıza gerek kalmaz. Yer tutucu argümanı parola istemi olarak yeniden kullanılıyor, bu nedenle bunu çağır

LD_PRELOAD=$PWD/injectpassword.so darkcoind masternode start "Password: "

Başka bir alternatif, şifreyi bir dosya tanımlayıcısından (örneğin gpg --passphrase-fd, yaptığı gibi ) veya x11-ssh-askpassveya herhangi bir şekilde okur .


4
Kodu anlamadığım ve test edemememe rağmen, onu anlıyorum ve bu gerçek bir cevap gibi görünüyor ve en iyi cevap olmalı.
Mark Henderson

Bu gerçekten harika.
Waqar Lim

Muhteşem. Bunu yapabildiğim kadarıyla çalışması gerektiğini söyleyebilirim. Tabii ki kaynağa erişmeniz ve yeniden derleyebilmeniz gerekir. Eğer "dizeleri" ya da benzer bir şey kullanırsanız, şifre kaynakta ve derlenen dosyalarda okunabilir, bu yüzden başka kimsenin bunları okuyamayacağından emin olun.
Tonny,

1
Şifreyi STDIN'e almak ve stringsgüvenlik açığını gideren bu çalışmaya devam etmek mümkün olmalıdır . Bkz : SO: Terminaldeki şifre girişini gizle .
Grubermensch

1
@ mulg0r: "extern" standart extern , ilgili fonksiyon için mangling ismini bastırma hilesini yerine getirmelidir __libc_start_main.
MvG

28

Bu sadece tarih değil. Ps çıkışında da ortaya çıkacak .

Bu yazılım parçasını kim yazdıysa asılmalı, çizilmeli ve dörtte bir kesilmelidir. Hangi yazılımda olursa olsun, komut satırında bir parola sağlamanız kesinlikle yasaktır.
Bir daemon süreci için bile affedilmez bile ...

Yazılımın kendisi üzerinde rm -f dışında bunun için herhangi bir çözüm bilmiyorum. Dürüst olmak gerekirse, işi yapmak için başka bir yazılım bulun. Böyle önemsiz kullanmayın.


9
Hiç yardımcı olmadığın için teşekkürler. Bu uzun zamandır tartışılan bir güvenlik sorunudur , hala çözülmedi ve rm -fşimdiden daha iyi bir geçici çözüme ihtiyacım var .
Waqar Lim

17
Aslında çok yardımcı oluyor. Eğer parolayı argüman olarak geçiyorsanız, görünecektir ps. Bu yüzden, geliştirici bunu çözene kadar başka bir şey kullanmanızı öneriyor
Safado

3
O zaman başka bir İşletim Sistemi yazmaya başlasan iyi edersin. Şu anda bildiğim kadarıyla mevcut başka bir çözüm yok. Tanrı tarafından keşke bir tane olsaydı. Bu sorunun tek sen değilsin.
Tonny

8
vertoe, snippy alamadım. Bunu küçük kağıt kâğıtlarına geçirmek için bir yol isteyebilirsiniz, ancak bu otomatik olarak herhangi bir yolun olduğu anlamına gelmez. read_x gayet iyi, ancak yine de şifreyi örneğin göstererek açıklıyor ps, bu yüzden rmçözümden daha iyi değil .
MadHatter, 15

7
Siz gitmeden ve bir cevap vermeden önce bir +1 atmadan ve bunun imkansız olduğundan şikayet etmeden önce, aşağıdaki MvG'nin cevabını
Mark Henderson

19

Bu psçıktıyı temizleyecektir .

ÇOK DİKKAT EDİN : Bu, uygulamayı bozabilir. Usulüne uygun olarak burada ejderha olduğu konusunda uyarılırsın.

  • Yabancı süreçler, süreç hafızasında dolandırılmamalıdır.
  • İşlem parola için bu bölgeye bağlıysa, başvurunuzu kırabilirsiniz.
  • Bunu yapmak, bu süreçte sahip olduğunuz çalışan verileri bozabilir.
  • Bu delilik bir kesmek.

Şimdi bu korkunç uyarılar hakkında usulüne uygun olarak bilgilendirilirsiniz. Bu, görüntülenen çıktıyı temizleyecektir ps. Geçmişinizi temizlemeyecek, ya da ash iş geçmişini de temizlemeyecektir (örneğin süreci yürütmek gibi myprocess myargs &). Fakat psartık argümanları göstermeyecek.

#!/usr/bin/python
import os, sys
import re

PAGESIZE=4096

if __name__ == "__main__":
  if len(sys.argv) < 2:
    sys.stderr.write("Must provide a pid\n")
    sys.exit(1)

  pid = sys.argv[1]

  try:
    cmdline = open("/proc/{0}/cmdline".format(pid)).read(8192)

    ## On linux, at least, argv is located in the stack. This is likely o/s
    ## independent.
    ## Open the maps file and obtain the stack address.
    maps = open("/proc/{0}/maps".format(pid)).read(65536)
    m = re.search('([0-9a-f]+)-([0-9a-f]+)\s+rw.+\[stack\]\n', maps)
    if not m:
      sys.stderr.write("Could not find stack in process\n");
      sys.exit(1)

    start = int("0x"+m.group(1), 0)
    end = int("0x"+m.group(2), 0)

    ## Open the mem file
    mem = open('/proc/{0}/mem'.format(pid), 'r+')
    ## As the stack grows downwards, start at the end. It is expected
    ## that the value we are looking for will be at the top of the stack
    ## somewhere
    ## Seek to the end of the stack minus a couple of pages.
    mem.seek(end-(2*PAGESIZE))

    ## Read this buffer to the end of the stack
    stackportion = mem.read(8192)
    ## look for a string matching cmdline. This is pretty dangerous.
    ## HERE BE DRAGONS
    m = re.search(cmdline, stackportion)
    if not m:
      ## cause this is an example dont try to search exhaustively, just give up
      sys.stderr.write("Could not find command line in the stack. Giving up.")
      sys.exit(1)

    ## Else, we got a hit. Rewind our file descriptor, plus where we found the first argument.
    mem.seek(end-(2*PAGESIZE)+m.start())
    ## Additionally, we'll keep arg0, as thats the program name.
    arg0len = len(cmdline.split("\x00")[0]) + 1
    mem.seek(arg0len, 1)

    ## lastly overwrite the remaining region with nulls.
    writeover = "\x00" * (len(cmdline)-arg0len)
    mem.write(writeover)

    ## cleanup
    mem.close()

  except OSError, IOError:
    sys.stderr.write("Cannot find pid\n")
    sys.exit(1)

Programı kaydederek çağırın chmod +x. Sonra yapmak ./whatever <pidoftarget> Eğer bu işe yararsa, hiç çıktı vermez. Başarısız olursa, bir şey hakkında şikayet eder ve istifa eder.


18
. . . bu hem yaratıcı hem de korkutucu.
voretaq7

EEK! Şimdi korktum.
Janne Pikkarainen

Yikkes, işe yarayabilir ... AppArmor gibi bir şeyin bunu yakalayacağından emin değilim. Ayrıca virusscanner bunu potansiyel olarak yakalayabilir ve “kök” olacak rahatsız edici hesabı bloke ederek tahribata yol açabilir. Gerçekten ejderhalar var ....
Tonny

@Tonny Korunan alanlar için SELinux bunu önler. Temel Unix izinleriniz (DAC) bu davranıştan herhangi bir koruma sağlamak için yeterli konu ayrıntı derecesine sahip değildir (aynı UID içindeki işlem belleğinin değiştirilmesine izin verir). Neyse, bu bir hata değil - bir özellik. Bunun gdbçalışan işlemlerin hafızasını nasıl değiştirebileceğime inanıyorum (ekleyebileceğimden çok daha fazla cerrahi hassasiyetle).
Matthew Ife

11

Argümanı yalnızca kök veya gerekli kullanıcı tarafından erişilebilen bir dosyadan geçirebilir misiniz?

Konsolda şifreleri yazmak BÜYÜK bir hayır-hayır, ancak son başvuru ... çizginize bir boşluk ile başlamak böylece tarihte görünmüyor.


Bunu sağlayan bir kabuk seçeneği vardı, ancak varsayılan olarak etkin olmadığını düşünüyorum.
heinrich5991

export HISTCONTROL=ignorebothGeçmişe giriş için hem kopyaları hem de satırları boş alan yok sayar. .Bashrc veya .bash_profile dosyasına ekleyin.
Andreas,

7

Belki bu çalışır (?):

darkcoind masternode start `cat password.txt`

3
Hatta darkcoind masternode start `head -1`şifreyi manuel olarak girmek istiyorsanız.
kasperd

14
Parola hala psve benzer yardımcı programlar yoluyla kullanılabilir .
voretaq7

1
Düz metin şifresinden düz metin şifresine .bash_historygeçmek password.txttam olarak ne kazanıyor?
MikeyB

1
@MikeyB: Küçük bir galibiyet var: Birisi omzunun üzerinden bakarken tarihini araştırırken kazara ifşa etmeyeceksin.
MvG

1
@MikeyB, her seferinde bu dosyayı oluşturabilir ve kaldırabilirsiniz.
RiaD

4

Maalesef, eğer darkcoindkomutunuz şifreyi bir komut satırı argümanı olarak beklerse, o zaman aşağıdaki gibi yardımcı programlara maruz kalacaktır ps. Tek gerçek çözüm geliştiricileri eğitmektir .

psPozlama kaçınılmaz olsa da, en azından parolanın kabuk geçmişi dosyasına yazılmasını engelleyebilirsiniz.

$ xargs darkcoind masternode start

password

CtrlD

Geçmiş dosyası sadece xargs darkcoind masternode startşifreyi değil kaydetmelidir .


2
Eğer bash kullanmanız durumunda ise, koyun ignorespaceiçinde $HISTCONTROLve sonra önleyebilir herhangi bir boşlukla komutu adýnýnönüne kabuk tarihinin geçmesini komutu.
derobert

3

Diğerlerinin de belirttiği gibi, geçmişten gelen bilgileri gizlemek için kabuk geçmişi kontrolünüze bakın.

Ancak henüz kimsenin önermediği bir şey var /proc, bu hidepidparametre ile bağlantı kurmak . Aşağıdaki gibi eklemek için /procsatırınızı değiştirmeyi deneyin :/etc/fstabhidepid

# <file system> <mount point>   <type>  <options>       <dump>  <pass>
proc            /proc           proc    defaults,hidepid=2        0       0

2

Komutu daha sonra hemen sonlandırdığınız yeni bir kabuk işleminden çalıştırarak şifreyi kabuk geçmişinizden uzak tutabilirsiniz. Örneğin:

bash$ sh
sh$ darkcoind masternode start 'correct horse battery staple'
sh$ exit
bash$

Yap emin shyapılandırıldı değil bir dosyaya tarihini kaydedin.

Tabii ki bu tür görünür olma şifre gibi diğer sorunları ele almaz ps. İnanıyorum ki darkcoindprogramın kendisinden bilgileri gizlemesinin yolları var ps, ancak bu sadece güvenlik açığını azaltan pencereyi kısaltıyor.


1
parola hala psve benzer yardımcı programlar yoluyla kullanılabilir .
voretaq7

3
@ voretaq7: Evet, cevabımın son paragrafında açıkça belirtildiği gibi.
Keith Thompson,

3
Gerçekten - sen benim tarafımdan wanton copypasta kurbanı oldun :)
voretaq7

2

Bitcoin için resmi geliştirici cevabı, sağlanan python sarmalayıcısını contrib/bitrpc/bitrpc.py( github ):

walletpassphraseÖrneğin , komutu kullanırsanız, güvenli bir şekilde bir şifre girmenizi ister . Etkileşimli işlevsellik eklemek için hiçbir plan yoktur bitcoin-cli.

ve:

bitcoin-cli olduğu gibi kalır ve etkileşimli işlevsellik kazanmaz.

Kaynak: # 2318

Cüzdanın kilidini aç:

$ python bitrpc.py walletpassphrase

Parolayı değiştir:

$ python bitrpc.py walletpassphrasechange

https://github.com/bitcoin/bitcoin/tree/master/contrib/bitrpc

Darkcoin için anlog çalışır:

https://github.com/darkcoin/darkcoin/tree/master/contrib/bitrpc

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.