Girilen şifre nasıl kontrol edilir bu kullanıcı için geçerli bir şifre?


15

Senaryo:

Bir bash betiğinde, bir kullanıcı tarafından verilen bir parolanın geçerli bir kullanıcı parolası olup olmadığını kontrol etmeliyim.

Ben pa PA pa sahip bir kullanıcı var varsayalım .. Senaryoda ben A kullanıcı şifresini girmek istedi, Peki girilen dize gerçekten onun şifre olup olmadığını nasıl kontrol etmek için? ...


Geçerli bir şifre ile ne demek istiyorsun? Gerçekten kullanıcının şifresi olup olmadığını test etmek ister misiniz?
AB

@AB geçerli şifre = ne demek istersen giriş şifresi ... Yani bu kullanıcı için bir şifre
Maythux

@AB Ben bir güvenlik deliği olacağını biliyorum ama burada zaten kullanıcı adını da biliyorsun ... Başka bir deyişle, şifre bu kullanıcı için ise sadece bir test ..
Maythux


Stackoverflow.com/a/1503831/320594expect adresinde bulunan bir çözüm .
Jaime Hablutzel

Yanıtlar:


15

Bunu bir kabuk komut dosyasında yapmak istediğiniz için , Linux ile parola nasıl kontrol edilir? (on Unix.SE , AB tarafından önerilen ) ile alakalı olan:

Bir dizenin gerçekten bir kullanıcının şifresi olup olmadığını manuel olarak kontrol etmek için, kullanıcının gölge girdisindeki ile aynı karma algoritma ile, kullanıcının gölge girdisindeki ile aynı tuzla hash etmeniz gerekir . Sonra orada saklanan şifre karma ile karşılaştırılabilir.

Bunu nasıl yapacağınızı gösteren eksiksiz, çalışan bir senaryo yazdım.

  • Adını chkpassverirseniz, çalıştırabilirsiniz ve standart girişten bir satır okuyacak ve şifresinin olup olmadığını kontrol edecektir .chkpass useruser
  • Bu komut dosyasının bağlı olduğu yardımcı programı edinmek için whois Whois yükle paketini yükleyin mkpasswd.
  • Bu komut dosyasının başarılı olması için kök olarak çalıştırılması gerekir.
  • Gerçek iş yapmak için bu komut dosyasını veya herhangi bir bölümünü kullanmadan önce lütfen aşağıdaki Güvenlik Notlarına bakın.
#!/usr/bin/env bash

xcorrect=0 xwrong=1 enouser=2 enodata=3 esyntax=4 ehash=5  IFS=$
die() {
    printf '%s: %s\n' "$0" "$2" >&2
    exit $1
}
report() {
    if (($1 == xcorrect))
        then echo 'Correct password.'
        else echo 'Wrong password.'
    fi
    exit $1
}

(($# == 1)) || die $esyntax "Usage: $(basename "$0") <username>"
case "$(getent passwd "$1" | awk -F: '{print $2}')" in
    x)  ;;
    '') die $enouser "error: user '$1' not found";;
    *)  die $enodata "error: $1's password appears unshadowed!";;
esac

if [ -t 0 ]; then
    IFS= read -rsp "[$(basename "$0")] password for $1: " pass
    printf '\n'
else
    IFS= read -r pass
fi

set -f; ent=($(getent shadow "$1" | awk -F: '{print $2}')); set +f
case "${ent[1]}" in
    1) hashtype=md5;;   5) hashtype=sha-256;;   6) hashtype=sha-512;;
    '') case "${ent[0]}" in
            \*|!)   report $xwrong;;
            '')     die $enodata "error: no shadow entry (are you root?)";;
            *)      die $enodata 'error: failure parsing shadow entry';;
        esac;;
    *)  die $ehash "error: password hash type is unsupported";;
esac

if [[ "${ent[*]}" = "$(mkpasswd -sm $hashtype -S "${ent[2]}" <<<"$pass")" ]]
    then report $xcorrect
    else report $xwrong
fi

Güvenlik Notları

Doğru yaklaşım olmayabilir.

Böyle bir yaklaşımın güvenli ve uygun bir şekilde değerlendirilip değerlendirilmeyeceği, kullanım durumunuzla ilgili belirtmediğiniz ayrıntılara bağlıdır (bu yazıdan itibaren).

Denetlenmemiştir.

Bu senaryoyu yazarken dikkatli olmaya çalışmama rağmen, güvenlik açıkları için uygun şekilde denetlenmedi . Bu bir gösterim amaçlıdır ve bir projenin parçası olarak yayınlandığında "alfa" yazılımı olacaktır. Dahası ...

"İzleyen" başka bir kullanıcı, kullanıcının tuzunu bulabilir .

mkpasswdTuz verilerinin kabulü konusundaki sınırlamalar nedeniyle , bu komut dosyası , kullanım durumuna bağlı olarak kabul edebileceğiniz veya kabul edemeyeceğiniz bilinen bir güvenlik açığı içerir . Varsayılan olarak, Ubuntu ve diğer birçok GNU / Linux sistemindeki kullanıcılar, komut satırı argümanları da dahil olmak üzere diğer kullanıcılar (kök dahil) tarafından çalıştırılan işlemler hakkındaki bilgileri görüntüleyebilir. Kullanıcının girişi veya saklanan parola karması, herhangi bir harici yardımcı programa komut satırı bağımsız değişkeni olarak geçirilmez. Ancak tuz elde, shadowveri tabanı, bir bir komut satırı parametre olarak verilen mkpasswdbu yarar, girdi olarak bir tuz kabul tek yoludur, çünkü.

Eğer

  • sistemdeki başka bir kullanıcı veya
  • herhangi bir kullanıcı hesabı (örn. www-data) kodunu çalıştırabilen herhangi biri veya
  • çalışan işlemler hakkında bilgileri başka bir şekilde görüntüleyebilen herkes (içindeki girişleri manuel olarak incelemek dahil /proc)

komut satırı bağımsız değişkenlerini mkpasswdbu komut dosyası tarafından çalıştırıldığı gibi denetleyebilir, ardından kullanıcının tuzunun bir kopyasını shadowveritabanından alabilir. Bu komutun ne zaman çalıştırıldığını tahmin edebilmeleri gerekebilir , ancak bu bazen elde edilebilir.

Tuzunuzla bir saldırgan, tuzunuz ve hashınızla bir saldırgan kadar kötü değil , ama ideal değil. Tuz, birisinin şifrenizi keşfetmesi için yeterli bilgi sağlamaz. Ancak birisinin , o sistemde o kullanıcıya özgü gökkuşağı tabloları veya önceden hesaplanmış sözlük karmaları oluşturmasına izin verir . Bu başlangıçta değersizdir, ancak güvenliğiniz daha sonraki bir tarihte tehlikeye girerse ve tam karma elde edilirse , değiştirme şansı elde etmeden önce kullanıcının şifresini almak daha hızlı bir şekilde kırılabilir .

Bu nedenle bu güvenlik açığı, tamamen sömürülebilir bir güvenlik açığından ziyade daha karmaşık bir saldırı senaryosunda ağırlaştırıcı bir faktördür. Ve yukarıdaki durumun çok zorlandığını düşünebilirsiniz. Ama genel, gerçek dünya kullanımı için herhangi bir yöntem tavsiye isteksiz sızıntı olduğunu herhangi olmayan halka açık veri /etc/shadowkök olmayan bir kullanıcıya.

Bu sorunu tamamen önleyerek şunları yapabilirsiniz:

  • siz, C işlevleri çağırmak Perl veya sağlayan başka bir dilde komut bölümünü yazma Gilles yanıtında gösterilen üzere ilgili Unix.SE soruya , ya
  • tüm betiğinizi / programınızı bash kullanmak yerine böyle bir dilde yazmak. (Soruyu etiketleme biçiminize göre, bash kullanmayı tercih ettiğiniz anlaşılıyor.)

Bu komut dosyasını nasıl çağırdığınıza dikkat edin.

Güvenilmeyen bir kullanıcının bu komut dosyasını kök olarak çalıştırmasına veya bu komut dosyasını çağıran herhangi bir işlemi kök olarak çalıştırmasına izin verirseniz, dikkatli olun . Ortamı değiştirerek, bu komut dosyasını veya kök olarak çalışan herhangi bir komut dosyasını herhangi bir şey yapabilirler . Bunun olmasını engelleyemediğiniz sürece, kullanıcıların kabuk komut dosyalarını çalıştırmak için yükseltilmiş ayrıcalıklara izin vermemelisiniz.

Bkz. 10.4. Bu konuda daha fazla bilgi için David A. Wheeler'ın Linux ve Unix NASIL için Güvenli Programlama'daki Kabuk Betik Dilleri (sh ve csh Türevleri) . Sunumu setuid komut dosyalarına odaklanırken, diğer mekanizmalar çevreyi doğru bir şekilde sterilize etmezlerse aynı sorunların bazılarına avlanabilir.

Diğer notlar

Sadece shadowveritabanından okuma karmaları destekler .

Bu komut dosyasının çalışması için parolalar gölgelenmelidir (yani, karmaları /etc/shadowyalnızca kökün okuyabileceği, içinde okuyabileceği ayrı bir dosyada olmalıdır /etc/passwd).

Bu her zaman Ubuntu'da geçerli olmalıdır. Gerekirse Her durumda, komut trivially gelen şifre sağlamalarının okumak için uzatılabilir passwdyanı sıra shadow.

Keep IFSBu komut dosyasını değiştirirken aklında.

IFS=$Başlangıçta ayarladım , çünkü bir gölge girdisinin karma alanındaki üç veri birbirinden ayrılıyor $.

  • Onlar da bir lider var $karma tip ve tuz neden olan "${ent[1]}"ve "${ent[2]}"yerine "${ent[0]}"ve "${ent[1]}"sırasıyla.

Bu komut dosyasında $IFSkabuğun sözcükleri nasıl böler veya birleştirdiğini belirleyen tek yerler

  • bu veriler bir diziye ayrıldığında, bu dizideki tırnaksız $( )komut ikamesinden başlatılarak :

    set -f; ent=($(getent shadow "$1" | awk -F: '{print $2}')); set +f
  • dizi, tam alanla karşılaştırılmak üzere bir dizeye yeniden oluşturulduğunda shadow, içindeki "${ent[*]}"ifade:

    if [[ "${ent[*]}" = "$(mkpasswd -sm $hashtype -S "${ent[2]}" <<<"$pass")" ]]

Komut dosyasını değiştirir ve başka durumlarda sözcük bölme (veya sözcük birleştirme) gerçekleştirmesini istiyorsanız, IFSkomutun farklı komutları veya farklı bölümleri için farklı değerlere ayarlamanız gerekir .

Bunu aklınızda $IFStutmazsanız ve normal boşluk ( $' \t\n') olarak ayarlandığını varsayarsanız , komut dosyanızın oldukça garip görünen bazı şekillerde davranmasını sağlayabilirsiniz.


8

Bunun için kötüye kullanabilirsiniz sudo. sudo, -lkullanıcının sahip olduğu sudo ayrıcalıklarını test etme ve -Sstdin'den şifreyi okuma seçeneğine sahiptir . Ancak, kullanıcı hangi yetki seviyesine sahip olursa olsun, başarılı bir şekilde kimlik doğrulaması yapılırsa sudoçıkış durumu 0 ile döner. Böylece, kimlik doğrulamasının çalışmadığının göstergesi olarak başka bir çıkış durumunu alabilirsiniz ( sudokendi başına herhangi bir sorun olmadığını varsayarak , izin hataları veya geçersiz sudoersyapılandırma).

Gibi bir şey:

#! /bin/bash
IFS= read -rs PASSWD
sudo -k
if sudo -lS &> /dev/null << EOF
$PASSWD
EOF
then
    echo 'Correct password.'
else 
    echo 'Wrong password.'
fi

Bu komut dosyası biraz sudoersyapılandırmaya bağlıdır . Varsayılan kurulumu üstlendim. Başarısız olmasına neden olabilecek şeyler:

  • targetpwveya runaspwayarlandı
  • listpw dır-dir never
  • vb.

Diğer sorunlar arasında (teşekkürler Eliah):

  • Yanlış denemeler giriş yapılacak /var/log/auth.log
  • sudokimlik doğrulaması yaptığınız kullanıcı olarak çalıştırılmalıdır. sudoÇalıştırabilmeniz için ayrıcalıklarınız olmadığı sürece sudo -u foo sudo -lS, komut dosyasını hedef kullanıcı olarak çalıştırmanız gerektiği anlamına gelir.

Şimdi, burada-docs'u kullanmamın nedeni gizli dinlemeyi engellemektir. Komut satırının bir parçası olarak kullanılan bir değişken, işlemleri incelemek için topveya psveya başka araçlar kullanılarak daha kolay bir şekilde ortaya çıkar .


2
Bu şekilde mükemmel görünüyor. Rağmen nadir sudokonfigürasyonları (dediğin gibi) ve kümeleri olan sistemlerde çalışmaz/var/log/auth.log her girişimin kayıtlarına sahip bu hızlı, basittir ve tekerleği yeniden icat etmek yerine mevcut bir yardımcı programı kullanır. Boşluk dolgulu kullanıcı girişi ve dolgulu olmayan parolalar için yanlış başarıların yanı sıra beyaz boşluk dolgulu kullanıcı girişi ve dolgulu parolalar için yanlış hataların önlenmesi IFS=için ayar yapmanızı öneririm read. (Çözümümde benzer bir hata vardı.) Ayrıca şifresi kontrol edilen kullanıcı olarak nasıl çalıştırılması gerektiğini de açıklamak isteyebilirsiniz.
Eliah Kagan

@EliahKagan başarısız olan her girişim günlüğe kaydedilir, ancak evet, diğer her şey hakkında haklısınız demektir.
muru

Başarılı kimlik doğrulama işlemleri de günlüğe kaydedilir. sudo -l" COMMAND=list" ile bir girişin yazılmasına neden olur . Btw (ilgisiz), nesnel olarak daha iyi olmasa da, burada bir belge yerine burada bir dize kullanmak aynı güvenlik hedefine ulaşır ve daha kompakttır. Betik zaten bashisms kullandığından read -sve &>kullanmak if sudo -lS &>/dev/null <<<"$PASSWD"; thendaha az taşınabilir değildir. Sahip olduklarınızı değiştirmenizi önermiyorum (sadece iyi). Aksine, okuyucular da bu seçeneğin olduğunu biliyorlar.
Eliah Kagan

@EliahKagan ah. düşündümsudo -l şeyi devre dışı bıraktığımı - belki de bir kullanıcı izin verilmeyen bir komutu çalıştırmaya çalıştığında rapor veriyordu.
muru

@EliahKagan Gerçekten. Herestringleri daha önce bu şekilde kullandım . Burada bir yorumlama altında çalışıyordum, bu da heredoclara yol açtı, ama sonra onları yine de tutmaya karar verdim.
muru

5

Başka bir yöntem (muhtemelen teorik içeriği için pratik uygulamalarından daha ilginçtir).

Kullanıcının şifreleri içinde saklanır /etc/shadow.

Burada saklanan şifreler, en son Ubuntu sürümleri kullanılarak şifrelenir SHA-512.

Özellikle, şifre oluşturulduktan sonra, açık metinlerdeki şifre tuzlanır ve şifrelenir SHA-512.

Bu durumda bir çözüm, verilen parolayı tuzlamak / şifrelemek ve verilen kullanıcının /etc/shadowgirişinde saklanan şifreli kullanıcının parolasıyla eşleştirmek olacaktır .

Parolaların her kullanıcıda nasıl saklandığına dair hızlı bir döküm sağlamak için /etc/shadow girişinde/etc/shadow bir kullanıcı için örnek bir giriş fooaşağıdadır bar:

foo:$6$lWS1oJnmDlaXrx1F$h4vuzZVBwIE1Z6vT7N.spwbxYig9e/OHOIH.VDv9JPaC3.OtTusPFzma7g.R/oSZFW5QOI7IDdDY01G0zTGQE/:16566:0:99999:7:::
  • foo: Kullanıcı adı
  • 6: şifrenin şifreleme türü
  • lWS1oJnmDlaXrx1F: şifrenin şifreleme tuzu
  • h4vuzZVBwIE1Z6vT7N.spwbxYig9e/OHOIH.VDv9JPaC3.OtTusPFzma7g.R/oSZFW5QOI7IDdDY01G0zTGQE/: SHA-512tuzlu / şifreli şifre

barVerilen kullanıcı için verilen şifreyi eşleştirmek fooiçin yapılacak ilk şey tuz elde etmektir:

$ sudo getent shadow foo | cut -d$ -f3
lWS1oJnmDlaXrx1F

Sonra tam tuzlanmış / şifrelenmiş şifreyi almalısınız:

$ sudo getent shadow foo | cut -d: -f2
$6$lWS1oJnmDlaXrx1F$h4vuzZVBwIE1Z6vT7N.spwbxYig9e/OHOIH.VDv9JPaC3.OtTusPFzma7g.R/oSZFW5QOI7IDdDY01G0zTGQE/

Daha sonra verilen şifre tuzlanabilir / şifrelenebilir ve /etc/shadow :

$ python -c 'import crypt; print crypt.crypt("bar", "$6$lWS1oJnmDlaXrx1F")'
$6$lWS1oJnmDlaXrx1F$h4vuzZVBwIE1Z6vT7N.spwbxYig9e/OHOIH.VDv9JPaC3.OtTusPFzma7g.R/oSZFW5QOI7IDdDY01G0zTGQE/

Eşleşiyorlar! Her şey birbash senaryoya :

#!/bin/bash

read -p "Username >" username
IFS= read -p "Password >" password
salt=$(sudo getent shadow $username | cut -d$ -f3)
epassword=$(sudo getent shadow $username | cut -d: -f2)
match=$(python -c 'import crypt; print crypt.crypt("'"${password}"'", "$6$'${salt}'")')
[ ${match} == ${epassword} ] && echo "Password matches" || echo "Password doesn't match"

Çıktı:

$ ./script.sh 
Username >foo
Password >bar
Password matches
$ ./script.sh 
Username >foo
Password >bar1
Password doesn't match

1
sudo getent shadow>> sudo grep .... Aksi takdirde, güzel. Aslında bunu düşündüm, sonra çok tembelleştim.
muru

@muru Teşekkürler. Kesinlikle daha güzel, çok güncellenmiş hissediyor, ama yine de bu durumda getent+ grep+ cut> grep+cut
kos

1
Eek. getentsizin için arama yapabilirsiniz. Düzenleme özgürlüğünü aldım.
muru

@muru Evet aslında sahip olmalısın, şimdi anlıyorum!
kos

2
Önyargılı olmama rağmen aslında bunun oldukça pratik olduğunu düşünüyorum: kullandığım yöntemle aynı. Uygulamanız ve sunumunuz oldukça farklı - bu kesinlikle değerli bir cevap. Kullandığım Oysa mkpasswdkullanıcı girişinden bir karma ve mevcut tuz üretmek için (ve ek özellikler ve teşhis dahil), bunun yerine uygulanması basit bir Python programı kodlu ettik mkpasswd'nin en önemli işlevsellik ve kullandık. Sana set tavsiye IFS=şifre girişi ve alıntı okurken ${password}ile "şifre girişi boşluk ile senaryoyu bozmaması için.
Eliah Kagan
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.