1

Topic: Root compromise

i found vulnerability in iredapd that can be exploited to gain root access.

Problem:
When plugins got loaded by iredAPD, it automatically compiles source .py files into .pyc files for faster loading in the future. But unfortunately the compiled file permission is world writable (666 mode). Since iredAPD run as root (root privilege for iredapd is too much), attacker can replace PYC plugins file with maliciously crafted PYC files to execute code with root privilege.

Attacker can prepare malicious PYC file on his own test box, then upload it to victim box and replace the original pyc file with his own.

It is easy to make PYC file by modifying original plugin .py file on attacker box, and then force it to apply plugins by sending mail or directly talking to port 7777. The first 8 byte of malicious pyc file must be exactly the same with the original pyc file on the victim box because modification time of .py file is recorded as header.

this vuln is tested successfully on iRedOS 0.6.0, the result is normal user gain root privilege.

Fix:
chmod 600 to /opt/iredapd/src/plugins/*.pyc and plugins-rr/*.pyc

To make it even more secure, on my production box, i do some modification of iredapd.py and iredapd-rr.py to make it run as non-root user. Line with --THIS IS MY CODE-- is my code to drop root privilege to normal user.

    # Run this program as daemon.
    if run_as_daemon == 'yes':
        daemon.daemonize()

    run_as_user = cfg.get('general','run_as_user','iredapd') # --THIS IS MY CODE --
    uid = pwd.getpwnam(run_as_user)[2] # --THIS IS MY CODE --

    try:
        # Write pid number into pid file.
        f = open(cfg.get('general', 'pid_file', '/var/run/iredapd.pid'), 'w')
        f.write(str(os.getpid()))
        f.close()

        os.setuid(uid); # --THIS IS MY CODE --

add this line:
import pwd
on top file after "import os" line.

In file iredapd.ini and iredapd-rr.ini, add this one line:
run_as_user     = iredapd

don't forget to add iredapd user.

restart iredapd and enjoy.. here is output of "ps aux" on my production box (iredapd is no longer run as root anymore):

iredapd    428  0.0  0.1  10780  3960 ?        S    15:16   0:00 python /opt/iredapd/src/iredapd.py /opt/iredapd/etc/iredapd.ini
iredapd  22917  0.0  0.1  10780  3964 ?        S    Jul19   0:03 python /opt/iredapd/src/iredapd-rr.py /opt/iredapd/etc/iredapd-rr.ini

2

Re: Root compromise

Great. I will fix it ASAP. big_smile

P.S, maybe running iRedAPD as 'nobody' is enough, no need to create user 'iredapd'.

3

Re: Root compromise

ZhangHuangbin wrote:

Great. I will fix it ASAP. big_smile

P.S, maybe running iRedAPD as 'nobody' is enough, no need to create user 'iredapd'.

I prefer using special user for better isolation, in some box nobody is used to run httpd which is dangerous in case web compromised occurs.

In my code, i made it parameterized so that user can choose which user to run iredapd as by editing iredapd.ini file.

4

Re: Root compromise

Yes, you're right. I will set it to 'nobody' by default, but will suggest users to create user 'iredapd' for this purpose.

5

Re: Root compromise

Making iredpad run as non-root user is not enough if it still produce pyc file in world-writable mode.

iredpd produce pyc file in rw-rw-rw mode because default value of UMASK constant in /opt/iredapd/daemon.py file is zero (0).

Change UMASK constant value in file /opt/iredapd/daemon.py to 0077 to ensure it will always produce pyc file in a non-world-writable mode.

6

Re: Root compromise

Great. How about 0277?

P.S. Already add 'run_as_user' parameter in iRedAPD:
http://code.google.com/p/iredmail/sourc … o=iredapd#

Thanks smile

7

Re: Root compromise

ZhangHuangbin wrote:

Great. How about 0277?

Hmm... i think 600 is secure enough, only the owner can read and write to it. Removing write bit doesn't make it more secure, in fact i'm a bit worried it gonna breaks when the process need to write to it for some reason.

ZhangHuangbin wrote:

P.S. Already add 'run_as_user' parameter in iRedAPD:
http://code.google.com/p/iredmail/sourc … o=iredapd#
Thanks smile

That's great. I see you also remove chdir part, i'm agree with you. chdir to current directory is pointless since we already here why bother change dir to the same place.

8

Re: Root compromise

rizkiwicaksono wrote:

I see you also remove chdir part, i'm agree with you. chdir to current directory is pointless since we already here why bother change dir to the same place.

To be honest, what i want to do is CHROOT to the directory, but i'm not sure why i made this stupid mistake. And i found it yesterday, that's terrible (although it doesn't matter at all).

9

Re: Root compromise

I just made video showing how to exploit this vuln and gain root privilege:

http://www.youtube.com/watch?v=23sq22lbzTQ

Since this vuln has been fixed in iredapd 1.3.3, i think it is safe now to move this topic to public forum to warn more user about this issue.