Kıvrılma, parolanın ps çıktısında görünmesini nasıl önler?


68

Bir süre önce curlkomut satırı argümanları olarak verilen kullanıcı adlarının ve parolaların psçıktıda görünmediğini fark ettim (tabii ki bash geçmişinizde görünse de).

Aynı şekilde görünmüyorlar /proc/PID/cmdline.

(Birleştirilmiş kullanıcı adı / şifre argümanının uzunluğu yine de elde edilebilir.)

Aşağıdaki gösteri:

[root@localhost ~]# nc -l 80 &
[1] 3342
[root@localhost ~]# curl -u iamsam:samiam localhost &
[2] 3343
[root@localhost ~]# GET / HTTP/1.1
Authorization: Basic aWFtc2FtOnNhbWlhbQ==
User-Agent: curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.15.3 zlib/1.2.3 libidn/1.18 libssh2/1.4.2
Host: localhost
Accept: */*



[1]+  Stopped                 nc -l 80
[root@localhost ~]# jobs
[1]+  Stopped                 nc -l 80
[2]-  Running                 curl -u iamsam:samiam localhost &
[root@localhost ~]# ps -ef | grep curl
root      3343  3258  0 22:37 pts/1    00:00:00 curl -u               localhost
root      3347  3258  0 22:38 pts/1    00:00:00 grep curl
[root@localhost ~]# od -xa /proc/3343/cmdline 
0000000    7563    6c72    2d00    0075    2020    2020    2020    2020
          c   u   r   l nul   -   u nul  sp  sp  sp  sp  sp  sp  sp  sp
0000020    2020    2020    0020    6f6c    6163    686c    736f    0074
         sp  sp  sp  sp  sp nul   l   o   c   a   l   h   o   s   t nul
0000040
[root@localhost ~]# 

Bu etki nasıl elde edilir? Kaynak kodunda bir yerde curlmi? (Bence bu bir curlözellik değil , bir özellik değil psmi? Veya bir tür çekirdek özelliği mi?)


Ayrıca: Bu, bir ikili çalıştırılabilir dosyanın kaynak kodunun dışından gerçekleştirilebilir mi? Örneğin, muhtemelen root izinleriyle birleştirilmiş kabuk komutlarını kullanarak?

Başka bir deyişle, bir şekilde keyfi bir kabuk komutuna ilettiğim bir çıkışın /procveya psçıkışın (aynı şey, sanırım) görünmesini tartışabilir miyim ? (Bunun cevabını "hayır" olarak tahmin ediyorum ama bu fazladan yarım soruyu dahil etmeye değer görünüyor.)



16
Cevap değil, bu yaklaşımın güvenli olmadığını unutmayın . Programın başlangıcı ile herhangi bir kullanıcının şifreyi okuyabileceği argüman dizgilerinin silinmesi arasında bir yarış penceresi vardır. Komut satırında hassas şifreleri kabul etmeyin.
R. ..

1
Gevşek bir şekilde ilişkili: Çevre değişkenleri kime ait? ve Uygulamadaki herhangi biri environdoğrudan ortam değişkenlerine erişmek için kullanıyor mu? - alt satır: argüman listesi, ortam değişkenleri listesi gibi, kullanıcı işlem belleğini okur / yazar ve kullanıcı işlemiyle değiştirilebilir.
Scott

1
@ JPhi1618, grepşablonunuzun ilk karakterini bir karakter sınıfı yapın. Örneğinps -ef | grep '[c]url'
Wildcard

1
@mpy, t çok karmaşık değil. Bazı regex'ler kendileri ile eşleşirken bazıları eşleşmiyor. curleşleşir curlancak [c]urleşleşmez [c]url. Daha fazla ayrıntıya ihtiyacın olursa yeni bir soru sor ve cevap vermekten mutlu olurum.
Joker

Yanıtlar:


78

Çekirdek bir işlemi gerçekleştirdiğinde, komut satırı argümanlarını işleme ait okuma-yazma belleğine kopyalar (yığında, en azından Linux'ta). İşlem, o hafızaya diğer hafızalar gibi yazabilir. Ne zaman psargüman görüntüler, bu sürecin hafızasına o belirli adreste saklanır neyse geri okur. Çoğu program orijinal argümanları korur, ancak bunları değiştirmek mümkündür. POSIX açıklamasıps devletler bu

Temsil edilen dizginin, başlatıldığında komuta geçirildiği haliyle argüman listesinin bir versiyonu olup olmadığı veya uygulama tarafından değiştirilebileceği gibi argümanların bir versiyonu olup olmadığı belirtilmez. Uygulamalar argüman listelerini değiştirebilmeye ve bu değişikliğin ps çıktısına yansıtılmamasına bağlı olamaz.

Bunun belirtilmesinin nedeni, çoğu unix varyantının değişikliği yansıtmasıdır, ancak diğer işletim sistemlerinde POSIX uygulamaları bunu yansıtmayabilir.

Bu özellik sınırlı kullanımlıdır, çünkü işlem keyfi değişiklikler yapamaz. En azından, argümanların toplam uzunluğu arttırılamaz, çünkü program psargümanları getirecek konumu değiştiremez ve alanı orijinal boyutunun ötesine uzatamaz. Uzunluk, sonunda boş baytlar koyarak etkili bir şekilde azaltılabilir, çünkü argümanlar C tarzı boş sonlandırılmış dizelerdir (sonunda sonunda bir sürü boş argüman olması ayrılamaz).

Gerçekten kazmak istiyorsanız, açık kaynaklı bir uygulamanın kaynağına bakabilirsiniz. Linux'ta, kaynağı psgöreceksiniz tüm ondan komut satırı argümanları okur, orada ilginç değil proc dosya sistemi içinde, . Bu dosyanın içeriğini oluşturan kod içinde, çekirdeğindedir in . (Erişilen işlemin belleğinin bir kısmı ) adresinden geçer için ; işlem başladığında bu adresler çekirdeğe kaydedilir ve daha sonra değiştirilemez./proc/PID/cmdlineproc_pid_cmdline_readfs/proc/base.caccess_remote_vmmm->arg_startmm->arg_end

Bazı ödüller, bu yeteneklerini durumlarını yansıtmak için kullanır; örneğin, veya veya argv[1]gibi bir dizeye değiştirirler . Birçok unix varyantı bunu yapacak bir işleve sahiptir. Bazı programlar bu yeteneği gizli verileri gizlemek için kullanır. İşlem başladığında komut satırı argümanları görülebildiğinden bunun sınırlı kullanım olduğunu unutmayın.startingavailableexitingsetproctitle

Çoğu üst düzey dil, bağımsız değişkenleri dize nesnelerine kopyalar ve orijinal depolamayı değiştirmenin bir yolunu vermez. İşte argvunsurları doğrudan değiştirerek bu yeteneği gösteren bir C programı .

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
    int i;
    system("ps -p $PPID -o args=");
    for (i = 0; i < argc; i++)
    {
        memset(argv[i], '0' + (i % 10), strlen(argv[i]));
    }
    system("ps -p $PPID -o args=");
    return 0;
}

Örnek çıktı:

./a.out hello world
0000000 11111 22222

argvCurl kaynak kodunda değişiklik görebilirsiniz . Kıvrılma bir tanımlayan fonksiyon cleanargolaraksrc/tool_paramhlp.c kullanan tüm boşluklar için bir bağımsız değişken değiştirmek için kullanılan memset. Gelen src/tool_getparam.cbu işlev redacting örneğin birkaç kez kullanılır kullanıcı şifresini . İşlev parametre ayrıştırma işleminden çağrıldığından, bir kıvrılma çağrısı sırasında erken gerçekleşir, ancak bu gerçekleşmeden önce komut satırını boşaltmak yine de tüm parolaları gösterecektir.

Bağımsız değişkenler işlemin kendi belleğinde saklandığından, bir hata ayıklayıcı kullanmak dışında dışarıdan değiştirilemez.


Harika! Bu yüzden, bu özellik snippet'iyle ilgili olarak, çekirdeğinizi işlemin orijinal komut satırı argümanlarının işlemin okuma-yazma hafızasının dışında (okuma-yazma hafızasındaki kopyaya ek olarak) saklamasını sağlamanın POSIX uyumlu olacağı anlamına geldiğini anlıyorum. ? Ve sonra, psişlemlerin okuma-yazma hafızasında yapılan değişiklikleri göz ardı ederek, bu çekirdek belleğinden çıkan argümanları rapor ettiniz mi? Fakat (eğer doğru anladıysam?) Çoğu UNIX varyasyonları eskisini bile yapmıyor ps, bu nedenle orijinal veriler hiçbir yerde tutulmadığından, ikincisini çekirdek değişiklikleri olmadan yapamazsınız?
Wildcard

1
@Wildcard Doğru. Orijinali koruyan Unix uygulamaları olabilir, ancak ortak olanların hiçbirinin yaptığını sanmıyorum. C dili içeriği verir argvgirdileri (eğer ayarlayamıyor Değiştirilecek argv[i], ancak yazabilir argv[i][0]yoluyla argv[i][strlen(argv[i])]), bu yüzden sürecin belleğinde bir kopyası olmalı.
Gilles,

2
Curl kaynak kodunda ilgili fonksiyon: github.com/curl/curl/blob/master/src/tool_paramhlp.c#L139
sebasth

4
@Wildcard, Solaris bunu yapar. / Usr / ucb / ps tarafından görülen komut satırı, sahip olunan (değiştirilebilir) kopyadır. / Usr / bin / ps tarafından görülen komut satırı çekirdeğe ait (değiştirilemez) kopyadır. Çekirdek sadece ilk 80 karakter olsa da tutar. Başka bir şey kısaltıldı.
BowlOfRed,

1
@Wildcard Gerçekten de sonunda boş olan değerler boş argümanlardır. Gelen psorada hiçbir şey yok, ama kaç tane boşluk kontrol ederseniz evet, bu bir fark yaratır ve daha doğrudan gelen gözlemleyebilirsiniz gibi çıktı, boş tartışmaların çok benziyordu /proc/PID/cmdline.
Gilles,

14

Diğer cevaplar soruyu genel olarak iyi cevaplar. Özel olarak " Bu etki nasıl elde edilir? Kaynak kıvrılma kodunda bir yerde mi var? "

Gelen bukle kaynak kodunun argümanı ayrıştırma bölümünde , -uaşağıdaki gibi bir seçenek ele alınır:

    case 'u':
      /* user:password  */
      GetStr(&config->userpwd, nextarg);
      cleanarg(nextarg);
      break;

Ve cleanarg()işlev aşağıdaki gibi tanımlanır :

void cleanarg(char *str)
{
#ifdef HAVE_WRITABLE_ARGV
  /* now that GetStr has copied the contents of nextarg, wipe the next
   * argument out so that the username:password isn't displayed in the
   * system process list */
  if(str) {
    size_t len = strlen(str);
    memset(str, ' ', len);
  }
#else
  (void)str;
#endif
}

Böylece açıkça görebiliyoruz ki, userername: password argümanı argvdiğer cevaplarda açıklandığı gibi boşlukların üzerine yazılmıştır.


Açıklamalı olarak cleanarg, cevabın soruyu istediği şeyi yaptığını söylemekten hoşlanırım !
Floris

3

Bir işlem sadece parametrelerini okuyamaz, aynı zamanda yazabilir.

Bir geliştirici değilim, bu yüzden bu şeylere aşina değilim, ancak çevre parametrelerinin değişmesine benzer bir yaklaşımla dışarıdan mümkün olabilir:

https://stackoverflow.com/questions/205064/is-there-a-way-to-change-another-processs-environment-variables


Tamam, ama örneğin çalıştırılması bash -c 'awk 1 /proc/$$/cmdline; set -- something; awk 1 /proc/$$/cmdline'en azından kabukta, parametreleri ayarlamanın çekirdeğin işlem parametreleri olarak gördüğü şeyi değiştirmekten farklı olduğunu gösterir.
Joker,

4
Bir kabuk komut dosyası içinde @Wildcard Pozisyonel argümanlar vardır başlangıçta kopyalar arasında bazı kabuk sürecin komut satırı argümanlarının. Çoğu kabuk, betiğin orijinal argümanları değiştirmesine izin vermez.
Gilles,

@Gilles, evet, yorumumun amacı buydu. :) Bir işlemin yapabileceği genel ifadenin (bu cevabın ilk cümlesi), mevcut kabuk özellikleriyle elde edilip edilmeyeceğine cevap vermemesi. Bunun cevabı, "hayır" gibi görünüyor, bu da sorumun en altında tahmin ettiğim şeydi.
Wildcard
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.